美文网首页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