美文网首页Android开发Android源码分析Android技术知识
Android源码系列五:AsyncTask源码剖析

Android源码系列五:AsyncTask源码剖析

作者: Taonce | 来源:发表于2019-05-27 19:53 被阅读11次

    AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)

    AsyncTask 是用来帮助我们更好的使用 ThreadHandler,最好是用于处理短时间异步任务。

    使用 AsyncTask 解决异步问题

    // 实现AsyncTask的子类
    class MyAsyncTask(val name: String) : AsyncTask<Params, Progress, Result>() {
    
        // 执行任务之前的准备工作,比如将进度条设置为Visible,工作在主线程
        override fun onPreExecute() {
            Log.d("async", "onPreExecute")
        }
    
        // 在onPreExecute()执行完之后立即在后台线程中调用
        override fun doInBackground(vararg params: String?): Any? {
            Log.d("async", "$name execute")
            Thread.sleep(1000)
            publishProgress(1)
            return null
        }
    
        // 调用了publishProgress()之后,会在主线程中被调用,用于更新整体进度
        override fun onProgressUpdate(vararg values: Int?) {
            Log.d("async", "progress is: $values")
        }
        
        // 后台线程执行结束后,会把结果回调到这个方法中,并在主线程中被调用
        override fun onPostExecute(result: Any?) {
            Log.d("async", "onPostExecute")
        }
    }
    
    // 调用
    MyAsyncTask("one").execute("")
    MyAsyncTask("two").execute("")
    MyAsyncTask("three").execute("")
    MyAsyncTask("four").execute("")
    
    // 结果
    19:29:01.472 1786-1805/com.taonce D/async: one execute
    19:29:02.514 1786-1832/com.taonce D/async: two execute
    19:29:03.868 1786-1833/com.taonce D/async: three execute
    19:29:04.871 1786-1833/com.taonce D/async: four execute
    

    AsyncTask 必须被子类实例化才能使用,其中必须要实现的方法是:doInBackground(vararg params: String?): Any? , 其余三个方法是可选取实现的,具体的解释在上面的代码中都解释过了。还剩下三个泛型参数,下面一一来解释下:

    • Params:执行任务所需要的信息;
    • Progress:执行任务的时候,对外发布的进度;
    • Result:任务执行完成后的结果。

    到这为止,你是否发现了一个现象,在结果打印的信息中,每个日志都是相隔1s,仔细看看是不是,暂且留下一个坑放着,后面会分析给大家听。下面开始进入源码分析:

    构造函数

    先简单的分析下构造函数中的代码:

    public AsyncTask(@Nullable Looper callbackLooper) {
        // 初始化mHandler,如果callbackLooper为空或者为sMainLooper,那就使用getMainHandler()的Handler
        // 否则使用传进来的callbackLooper
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
        // 初始化一个WorkerRunnable对象,它是Callable的实现类,它的call()方法可以拥有返回值
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                ...
            }
        };
        // 初始化FutureTask对象,它传入了mWorker对象
        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                ...
            }
        };
    }
    

    mWorkermFuture 暂时不分析,等到调用的时候我们再结合源码看,目前我们只需要知道初始化了这些对象就够了。

    execute()

    接着我们来看看执行一个任务的入口 execute()

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        // 调用executeOnExecutor(executor,params),传入的是sDefaultExecutor
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                // 这里解释了为什么不能重复调用execute()方法
                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)");
            }
        }
        // 将状态标记为Running
        mStatus = Status.RUNNING;
        // 调用onPreExecute(),它是最先调用的
        onPreExecute();
        // 将params传给mWorker
        mWorker.mParams = params;
        // 执行sDefaultExecutor.execute(runnable)方法
        exec.execute(mFuture);
        // 返回自身
        return this;
    }
    

    我们调用 AsyncTask.execute(parasm) 方法其实就是调用了 sDefaultExecutor.execute(mFuture) 方法,我们顺藤摸瓜下去。

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    
    private static class SerialExecutor implements Executor {
        // 双端队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
    
        public synchronized void execute(final Runnable r) {
            // 添加到队列中,并且执行runnable.run()
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        // 执行完r.run()之后依旧会调用一次scheduleNext()方法
                        // 也就是循环的取队列中的Runnable,直到Runnable为空
                        // 从这里就可以看出,任务都是按照串行的形式来执行的,必须等待一个任务执行完毕才去取队列中的下一个,也就解释了开头的每个日志打印相隔1s的原因。
                        scheduleNext();
                    }
                }
            });
            // mActive第一次必然为空
            if (mActive == null) {
                scheduleNext();
            }
        }
    
        protected synchronized void scheduleNext() {
            // 从队列中取出Runnable,并且让线程池去执行
            // THREAD_POOL_EXECUTOR是一个线程池,配置在源码的最上方
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
    

    SerialExecutor 就是一个实现了 Executor 的静态内部类,它的 execute(runnable) 接收 Runnable 对象,然后在 executeOnExecutor(Executor exec, Params... params) 方法中传入的是 mFuture 对象,所以在执行到 scheduleNext() 的时候,就会调用 mFuturerun() 方法。

    FutureTask.run()

    public void run() {
        ...
        try {
            // 拿到Callable对象
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    // 执行Callable.call()方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    // 将Callable.call()方法set()起来,可通过get()获取
                    set(result);
            }
        }...
    }
    

    FutureTask.run() 方法就是调用它的 Callable 变量的 call() 方法,在 AsyncTask 中,传入的 Callable 就是 mWorker 对象,这时候我们就可以把构造函数中的 mWorker 初始化的代码搬出来读一读了。

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                // 获取doInBackground(params)的返回值
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                // 出现异常将mCancelled设置为true
                mCancelled.set(true);
                throw tr;
            } finally {
                // 回调结果
                postResult(result);
            }
            return result;
        }
    };
    
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }
    

    mWorker 其实很简单,就是拿到 doInBackground(params) 的返回值,无论是否出现异常,都将结果回调到主线程,回调的操作看下面的 postResult(result)

    private Result postResult(Result result) {
        // getHandler()就是获取mHandler对象,默认绑定的是主线程Looper
        // 而mHandler在构造函数中已经解释过,拿到的就是sHandler
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    

    通过 getHandler().obtainMessage()获取一个 Message 对象,将消息的 what 设置为 MESSAGE_POST_RESULT 标记为结果不是进度,obj 设置为 AsyncTaskResult 对象,它是一个内部类,包含了 AsyncTaskData[] 两个参数。通过 sHandler 将消息发送出去,然后我们看看它是怎么将 onPostExecute(result) 联系起来的。

    sHandlerInternalHandler 的实例,我们从 InternalHandler 的源码中就能得到想要的答案:

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

    InternalHandler 判断了消息的类型,一种是结果,一种是进度,如果是结果的话,那么就调用 AsyncTaskfinish() 方法;如果是进度的话,那么就调用 onProgressUpdate() 方法,这个方法在前面就已经介绍过了,就是更新整体进度的方法,我们只要看下 finish() 方法就ok了:

        private void finish(Result result) {
            // 任务是否被取消
            if (isCancelled()) {
                // 任务被取消的话,那么就调用onCancel(),这个方法也是可以重写的
                onCancelled(result);
            } else {
                // 没有被取消就去调用onPostExecute()
                onPostExecute(result);
            }
            // 将状态置为FINISHED
            mStatus = Status.FINISHED;
        }
    

    源码分析到此的话,大致的流程已经完成了,通过 execute() 方法将需要执行的任务添加到 SerialExecutor 的双端队列中,然后让 THREAD_POOL_EXECUTOR 线程池去依次执行队列中的 FutureTask.run() ,这里需要注意,执行任务是一个一个执行,执行结束之后再去执行另外一个,这个线程池相当于单线程模式,以串行的形式来执行任务的,而不是并行来执行,整个线程池中真正工作的只有那一个核心线程。通过执行 FutureTask.run() 方法去间接执行 mWorker.call() 方法,在 call() 方法中获取 doInBackground() 方法返回的结果,最后通过 postResult()InternalHandler 来将结果回调到 onPostExecute() 方法中。

    源码分析的文章还在不断的更新,如果本文章你发现有不正确或者不足之处,欢迎你在下方留言或者扫描下方的二维码留言也可!

    相关文章

      网友评论

        本文标题:Android源码系列五:AsyncTask源码剖析

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