【Android】AsyncTask源码解析

作者: 秀叶寒冬 | 来源:发表于2019-07-05 12:02 被阅读4次

    1 AsyncTask简介

    AsyncTask<Params, Progress, Result>

    • Params:启动任务执行的输入参数,如doInBackground的输入参数
    • Progress:后台任务执行的百分比,如on
    • Result:后台任务执行最终返回的结果,比如doInBackground返回值类型以及onPostExecute的输入参数。
    1. execute(Params... params):执行一个异步任务,需要我们手动去调用此方法,触发异步任务的执行。
    2. onPreExecute():在execute(params... params)被调用后立即执行,一般用来在执行后台任务前做一些准备工作。
    3. doInBackground(Params... params):在onPreExecute()完成后立即执行,用于执行耗时操作,在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
    4. onProgressUpdate(Progress... values):在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。
    5. onPostExecute(Result result):当后台操作结束时,此方法将会被调用,计算结果将作为参数传递到此方法中,直接将结果显示到UI组件上。

    2 AsyncTask执行流程

    按照AsyncTask执行顺序来,AsyncTask构造方法--->execute--->onPreExecute--->doInBackground、onProgressUpdate()--->onPostExecute

    1. AsyncTask初始化时会初始化一个Handler、WorkRunnable和FutureTask对象,该Handler默认调用的是主线程的Looper,WorkRunnable实现了Callable接口
    2. AsyncTask是用线程池来执行任务的。在调用execute方法时,会调用onPreExecute,然后调用ThreadPoolExecutor的execute方法来执行FutureTask,而WorkRunnable被传入到FutureTask中,因此会调用WorkRunnable里面的call方法。
    3. 在WorkRunnable里面的call方法中会执行doInBackground方法,且call方法最终会调用postResult方法,该方法中将最终结果封装到Message中,然后通过Message.sendToTarget最终将消息传入到消息队列中。
    4. Looper从MessageQueue中取出消息交给Handler处理,然后根据需求调用onPostExecute和onProgressUpdate。

    2.1 AsyncTask构造方法

        public AsyncTask() {
            this((Looper) 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);
                    }
                }
            };
        }
        
    

    这里实例化了一个Handler,WorkerRunnable和FutureTask对象,WorkerRunnable对象实现了Callable接口,如果没有指定Looper,则使用的是主线程的Looper

    2.2 execute

        public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
        private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
        private volatile Status mStatus = Status.PENDING;//默认没有被执行
    
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }
    
        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;
        }
    

    分析:调用execute方法时,会调用executeOnExecutor方法,该方法传入了两个参数,其中一个是sDefaultExecutor,该sDefaultExecutor被实例化为SerialExecutor对象。在executeOnExecutor方法里,首先判断AsyncTask状态,AsyncTask默认状态是未被执行,如下所示,AsyncTask状态有以下几种:

    public enum Status {
            /**
             * Indicates that the task has not been executed yet.
             * 表示该任务还没有被执行
             */
            PENDING,
            /**
             * Indicates that the task is running.
             * 表示该任务正在被执行
             */
            RUNNING,
            /**
             * Indicates that {@link AsyncTask#onPostExecute} has finished.
             * 表示该任务已经被完成
             */
            FINISHED,
        }
    

    2.3 onPreExecute

    在executeOnExecutor判断,如果AsyncTask没有被执行,则执行接下来的操作;如果被执行了,则抛出异常。如果AsyncTask没有被执行,则将状态设置为运行中,并调用onPreExecute()方法,该方法是一个空的方法,具体内容需要自己重写,而且它是运行在主线程中的。

        @MainThread
        protected void onPreExecute() {
        }
    

    2.4 doInBackground

    在executeOnExecutor里,接下来继续执行,将execute传入的参数存放在mWorker.mParams中,mWorker是WorkerRunnable对象,实现了Callable接口,这里可以参考【线程创建的四种方式】中使用Callable和Future来创建线程。这里有些许不同,这里是通过线程池来加载FutureTask的。接下来执行exec.execute(mFuture);exec是executeOnExecutor传入的第一个参数,是SerialExecutor对象。所以调用的是SerialExecutor里的execute方法

    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);
                }
            }
        }
    

    该方法会将FutureTask存入一个双端数组队列中,然后从队列中取出FutureTask并交给threadPoolExecutor执行,关于线程池可以参考【Android 线程池原理及使用】

        static {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                    sPoolWorkQueue, sThreadFactory);
            threadPoolExecutor.allowCoreThreadTimeOut(true);
            THREAD_POOL_EXECUTOR = threadPoolExecutor;
        }
    

    当线程池执行时,就会执行FutureTask,FutureTask会先执行WorkerRunnable的call方法,在call方法中调用doInBackground方法

        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;
                }
            };
    

    当doInBackground执行完后,会调用postResult

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

    在postResult中,会通过message.sendToTarget()将详细发送到MessageQueue中存储,接下来就是消息机制了,MessageQueue接收到消息后会将Message存入到消息队列中,然后如果Looper被阻塞,则唤醒Looper,Looper被唤醒后会无限循环从MessageQueue中取出消息,然后将取出的消息通过msg.target.dispatchMessage发送给执行的Handler进行处理,然后handler调用handleMessage处理消息,这段可参考【Android消息机制】

    private static class InternalHandler extends Handler {
            public InternalHandler(Looper looper) {
                super(looper);
            }
    
            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
            @Override
            public void handleMessage(Message msg) {
                AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
                switch (msg.what) {
                    case MESSAGE_POST_RESULT:
                        // There is only one result
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }
    

    如上述代码所示,msg.what=MESSAGE_POST_PROGRESS时,调用onProgressUpdate方法,msg.what=MESSAGE_POST_RESULT时调用finish方法,该finish方法中将结果返回给onPostExecute方法

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

    2.5 onPostExecute

    onPostExecute方法是一个空方法,需要自己重写

        protected void onPostExecute(Result result) {
        }
    

    3 流程总结

    1. AsyncTask初始化时会初始化一个Handler、WorkRunnable和FutureTask对象,该Handler默认调用的是主线程的Looper,WorkRunnable实现了Callable接口
    2. AsyncTask是用线程池来执行任务的。在调用execute方法时,会调用onPreExecute,然后调用ThreadPoolExecutor的execute方法来执行FutureTask,而WorkRunnable被传入到FutureTask中,因此会调用WorkRunnable里面的call方法。
    3. 在WorkRunnable里面的call方法中会执行doInBackground方法,且call方法最终会调用postResult方法,该方法中将最终结果封装到Message中,然后通过Message.sendToTarget最终将消息传入到消息队列中。
    4. Looper从MessageQueue中取出消息交给Handler处理,然后根据需求调用onPostExecute和onProgressUpdate。

    4 细节

    1. AsyncTask的execute方法每次只能执行一次
    2. 使用的线程池,则可以复用线程池里的线程,减少了开销,提升了性能

    相关文章

      网友评论

        本文标题:【Android】AsyncTask源码解析

        本文链接:https://www.haomeiwen.com/subject/onvshctx.html