源码颇析AsyncTask工作原理

QuibblerQuibbler 2020-04-25 约 27 分钟 1788 次阅读

源码颇析AsyncTask工作原理

Android开发中经常会用到AsyncTask开启异步任务,后台执行耗时操作,具体用法参考《AsyncTask:异步任务》。现在从源码来看看AsyncTask的实现机制。

1、AsyncTask中的线程池

AsyncTask中封装了两种Executor,一个是顺序执行的SERIAL_EXECUTOR,另一个是并发执行的THREAD_POOL_EXECUTOR。

1.1、SERIAL_EXECUTOR

sDefaultExecutor:默认的任务执行器。

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

SERIAL_EXECUTOR是SerialExecutor类型的线程池。

/**
     *  可以按顺序一次执行一个任务
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

SerialExecutor定义在AsyncTask中的静态内部类:

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

1.2、THREAD_POOL_EXECUTOR

THREAD_POOL_EXECUTOR并发执行任务的线程池,初始化如下:

/**
     * Executor可用于并行执行任务
     */
    public static final Executor THREAD_POOL_EXECUTOR;
    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), sThreadFactory);
        threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

配套的一线参数:核心线程数、最大线程数等定义如下,随着Android API版本的升级可能不太一样,以前定义的是和CPU核数有关,现在是写死的固定数值。

private static final int CORE_POOL_SIZE = 1;
    private static final int MAXIMUM_POOL_SIZE = 20;
    private static final int BACKUP_POOL_SIZE = 5;
    private static final int KEEP_ALIVE_SECONDS = 3;
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

2、AsyncTask创建初始化

2.1、AsyncTask构造函数

默认无参构造函数:必须在UI主线程上调用构造函数。

/**
     * 创建一个新的异步任务。必须在UI线程上调用此构造函数。
     */
    public AsyncTask() {
        this((Looper) null);
    }

外一个有参构造函数,传入的是Handler。

public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

前面这两个够构造函数最终调用的都是:

public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

2.2、内部Handler:线程间通信

初始化内部Handler mHandler。同时还提供一个私有get方法获取当前AsyncTask的Handler,当然是为了内部方便。

private final Handler mHandler;
    
    private Handler getHandler() {
        return mHandler;
    }

通过方法getMainHandler()获取内部定义的InternalHandler类型的静态成员变量sHandler,赋值给当前AsyncTaskmHandler。

private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

InternalHandler是定义在AsyncTask中的静态内部类,可以看到主要处理子线程中执行发出的消息:MESSAGE_POST_RESULT、MESSAGE_POST_PROGRESS。也就是执行结果和执行进度,这两个方法是运行在主线程的。

private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }
 
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // 只有一个结果
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

AsyncTaskResult是内部封装的当前AsyncTask和数据(执行结果/执行进度),方便通过Message的obj一次携带传回到主线程。

private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;
        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

2.3、构造Callable和FutureTask

两个重要的变量:Callable:mWorker和FutureTask:mFuture。

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

mWorker是Callable接口类型,不过多封装了一下,为了传入运行时的参数mParams。

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

注意一个细节,虽然AsyncTask到这里已经初始化完毕,但是有一点:执行时的参数mParams还是空的,并没有赋值,在真正调用AsyncTask的execute(...)方法传入参数才进行初始化。

result = doInBackground(mParams);

3、AsyncTask执行流程

3.1、执行AsyncTask

execute(Params... params)开始,当然也可以直接调用executeOnExecutor()方法传入指定的执行器。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

executeOnExecutor()方法:传入sDefaultExecutor。

①执行前先调用了onPreExecute(),也就是执行前的准备工作。

②同时也初始化mWorker中的mParams参数,前面构造AsyncTask的时候改参数并没有初始化,在执行的时候用到。

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }
        mStatus = Status.RUNNING;
        onPreExecute();
        mWorker.mParams = params;
        exec.execute(mFuture);
        return this;
    }

注意:这里判断了任务的状态如果已经执行完或者正在执行就会抛出异常。也就是为什么AsyncTask对象创建只能执行一次,如果再次调用,会抛出异常。

/**
     * 指示任务的当前状态。 在任务的生命周期内,每个状态只能设置一次。
     */
    public enum Status {
        /**
         * 指示任务尚未执行。
         */
        PENDING,
        /**
         * 表示任务正在运行。
         */
        RUNNING,
        /**
         * 表示onPostExecute已完成。
         */
        FINISHED,
    }

3.2、execute

在指定或者默认的线程池上执行任务,注意在mWorker中的call()方法运行在子线程,所以doInBackground(mParams)运行在子线程执行耗时任务。

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

并且在执行完之后调用postResult。

3.3、结果:onPostExecute(Result result)

子线程中执行完doInBackground(mParams)无论失败成功,finally都会执行将结果post出来。

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

在子线程中调用的postResult()通过mHandler切回到主线程执行,更新UI通知结果。

...
    case MESSAGE_POST_RESULT:
        // There is only one result
        result.mTask.finish(result.mData[0]);
        break;

result就是封装的AsyncTaskResult,传递当前AsyncTask和结果数据,mTask就是当前AsyncTask对象,调用finish()。

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

运行在主线程中,回调onPostExecute(Result result)并将当前AsyncTask标记为FINISHED。

3.4、更新进度:onProgressUpdate(Progress... values)

在doInbackground()方法中调用publishProgress(Progress... ) 就可以触发onProgressUpdate(Progress... values)方法,在UI线程中执行UI更新等任务。

protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

也是通过前面构造函数初始化的mHandler,向主线程发送Message,携带AsyncTask和进度。回到主线程Handler中执行,参考InternalHandler部分源码:

...
    case MESSAGE_POST_PROGRESS:
         result.mTask.onProgressUpdate(result.mData);
         break;

在主线程中执行onProgressUpdate(Progress... values)更新执行进度。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w