AsyncTask 完全解析

引言

我们知道,在 Android 中,UI 线程不能执行耗时操作;在子线程中不能执行更新 UI 的操作。如果需要在子线程中进行 UI 相关的操作,那么就需要借助 Android 中的异步消息机制(比如我们熟悉的Handler消息机制)才能完成。如果我们自己写代码来进行相关的处理,不仅麻烦,而且大部分的代码都是相同的,AsyncTask 的出现就能帮我们省去大部分的代码,并且可以非常灵活方便地从子线程切换到UI线程。今天就从 AsyncTask 的简单使用到源码进行解析,一步一步看看他是怎么实现的。

AsyncTask 的简单使用

创建 AsyncTask 实现类

class DownLoadAsyncTask extends AsyncTask {    @Override    protected Boolean doInBackground(String... params) {        // 运行在子线程,执行访异步任务        Log.i("DownLoadAsyncTask", "doInBackground(): 开始执行异步任务");        // publishProgress(Integer); // 调用更新进度方法        return downLoadImage(params[0]); // 下载图片方法    }    @Override    protected void onPreExecute() {        // 运行在主线程,异步任务执行前的准备工作        Log.i("DownLoadAsyncTask", "onPreExecute(): 执行异步任务前的准备工作");        super.onPreExecute();    }    @Override    protected void onPostExecute(Boolean result) {        // 运行在主线程,异步任务执行完成之后的回调        Log.i("DownLoadAsyncTask", "onPostExecute(): 异步任务执行完成之后的回调 => " + result);        super.onPostExecute(result);    }    @Override    protected void onProgressUpdate(Integer... progresses) {        // 运行在主线程,用于更新进度        // 注意:该方法需要在doInBackground()内部调用publishProgress()方法并传递进度,否则不会执行        Log.i("DownLoadAsyncTask", "onProgressUpdate(): 用于更新进度");        super.onProgressUpdate(progresses);    }}

AsyncTask

源码解析

构造方法

public AsyncTask() {    this((Looper) null);}public AsyncTask(@Nullable Handler handler) {    this(handler != null ? handler.getLooper() : null);}/** * @hide */public AsyncTask(@Nullable Looper callbackLooper) {    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()        ? getMainHandler()        : new Handler(callbackLooper);    mWorker = new WorkerRunnable() {        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(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);            }        }    };}

构造方法说明:

  1. 最终调用的都是AsyncTask(@Nullable Looper callbackLooper)方法,但是这个方法使用了@hide注解,开发者并不能直接调用。构造方法虽然比较长,但是他并没有任何的操作被执行,只是初始化了mHandlermWorkermFuture几个变量,并且将 mWorker 对象作为 mFuture 的构造方法参数传递给了 mFuture 对象。
  2. mHandler 是MainHandler
  3. 有一点需要注意:构造方法只能在UI线程中调用

构造方法中用到的部分对象说明:

  1. mHandler:Android Handler消息机制中的Handler对象,这里是InternalHandler对象,暂时记住就行了,后面会粘贴出具体实现的代码和说明
    class InternalHandler extends Handler:
  2. mWorker:实现 Callable 接口的 AsyncTask 类的内部类 WorkerRunnable
  3. mFuture:FutureTask 对象。FutureTask 对象的继承关系
    1. class FutureTask implements RunnableFuture
    2. interface RunnableFuture extends Runnable, Future

执行异步任务方法

public final AsyncTask execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);// 调用内部方法}public final AsyncTask 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; // 将状态设置为RUNNING    onPreExecute(); // 回调异步任务执行前的准备工作方法    mWorker.mParams = params; // 将传递的参数赋值给 mWorker 对象的 mParams 字段    exec.execute(mFuture); // 执行 mFuture    return this;}

到这一步的时候,我们的任务已经切换子线程中了。

方法说明:

  1. 判断当前的状态,如果是RUNNING或者是FINISHED就抛出异常
  2. 执行回调方法 onPreExecute() ,执行异步任务前的准备工作,比如显示进度对话框等
  3. mFuture 对象 交给 exec.execute(mFuture) 执行

exec.execute(mFuture)说明:

exec:即 sDefaultExecutor;实现 Executor接口的内部类 SerialExecutor

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static class SerialExecutor implements Executor {    final ArrayDeque mTasks = new ArrayDeque();    Runnable mActive;    public synchronized void execute(final Runnable r) {        mTasks.offer(new Runnable() {            public void run() {                try {                    r.run(); // 调用参数 Runnable 对象的 run() 方法                } finally {                    scheduleNext();                }            }        });        if (mActive == null) {            scheduleNext();        }    }    protected synchronized void scheduleNext() {        if ((mActive = mTasks.poll()) != null) {            THREAD_POOL_EXECUTOR.execute(mActive);        }    }}

通过上面 SerialExecutor 类的定义,我们可以看到 execute() 方法调用了它的参数(即mFuture)的run()方法,我们继续查看mFuturerun() 方法

public void run() {    if (state != NEW ||        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))        return;    try {        Callable c = callable;        if (c != null && state == NEW) {            V result;            boolean ran;            try {                result = c.call();                ran = true;            } catch (Throwable ex) {                result = null;                ran = false;                setException(ex);            }            if (ran)                set(result);        }    } finally {        runner = null;        int s = state;        if (s >= INTERRUPTING)            handlePossibleCancellationInterrupt(s);    }}

在该方法中主要是调用了 callable 对象的 call() 方法,我们一起看看 callable对象是从哪里来的。

public FutureTask(Callable callable) {    if (callable == null)        throw new NullPointerException();    this.callable = callable;    this.state = NEW;       // ensure visibility of callable}

查看 FutureTask 对象的构造方法,我们发现callable对象是在构造方法中初始化的。好,我们现在就只要知道 FutureTask 对象是在哪里初始化的,就知道 call() 方法的具体执行内容是什么了。那么你是否还记得我们在查看 AsyncTask 类的构造方法时看到了它初始化几个变量就有FutureTask 对象,所以在这里执行的 call() 方法具体的方法体就是在AsyncTask 类的构造方法总中定义的方法体。为了方便观察,我把这段代码在粘贴一次:

mWorker = new WorkerRunnable() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Result result = null;            try {                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                result = doInBackground(mParams); // 执行 doInBackground 回调方法,参数在mParams的值在executeOnExecutor()中初始化了                Binder.flushPendingCommands();            } catch (Throwable tr) {                mCancelled.set(true);                throw tr;            } finally {                postResult(result); // 设置结果            }            return result;        }    };

看了这么久的代码,我们总算看到了执行任务的方法,也就是我们的重写方法 doInBackground(mParams) 返回的 Result 是结果泛型类型(第三个泛型的类型),在上面说过了三个泛型表示的意义;也就是说,到了这一步,我们的异步任务真正的开始执行了;我们接着看finally中的代码,调用的 postResult(result) 方法,看看这个方法的具体实现:

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

在这个方法中使用了一个新的类 AsyncTaskResult,它也是 AsyncTask 的内部类,定义如下:

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

回过头在看 postResult(Result result) 这个方法中的代码非常简单,getHandler()方法获取到我们在构造方法中初始化的 mHandler 对象,接着获取一个 Message 对象并且创建一个 AsyncTaskResult 对象(这个对象包含了AsyncTask 类的本类对象和 doInBackground()方法返回的结果对象2个参数)作为消息的内容,最后将这个消息发送到目标 mHandler 。上面说过了这个mHandlerInternalHandler,但是没有贴出具体实现的代码,那么现在我们就来看一下它到底做了些什么(InternalHandler类是AsyncTask类的内部类):

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

这段代码我想大家都能看懂吧,最常见的 Handler 写法,通过判断 Messagewhat 进行不同的操作(任务执行完成或者更新进度)。我们只需要弄清楚 result.mTask 表示的哪一个对象就可以知道调用的方法是什么了。
postResult(Result result)方法中,我们知道了 Messageobj 字段的值是 AsyncTaskResult 对象,参数是 thisdoInBackground()方法返回的结果对象,很容易知道this表示 AsyncTask 本类对象;在通过 AsyncTaskResult 的构造方法我就知道 result.mTask 就是AsyncTask 的本类对象,所以我们就知道了 result.mTask.finish(result.mData[0]) 方法就是AsyncTask 类的 finish(Result result) 方法了;同理result.mTask.onProgressUpdate(result.mData) 方法就是AsyncTask 类的 onProgressUpdate(Progress... values) 方法。

看看AsyncTask 类的 finish(Result result) 方法:

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

方法说明:

  1. 判断是不是取消了,如果取消了,就回调 onCancelled() 方法(开发者重写)
  2. 如果没有取消就回调 onPostExecute(Result result) 方法(开发者重写)
  3. 将任务的执行状态改变为 FINISHED

到此为止,我们发现的任务执行前的准备方法onPreExecute()、任务执行方法 doInBackground 以及 取消方法 onCancelled() 和完成方法 onPostExecute() 都成功回调了;但是我们更新进度的方法 onProgressUpdate() 却并没有在哪里有调用;如果看的比较知仔细的可能已经发现了,我在第一部分简单使用中说明了:

那么我们看看 publishProgress(Progress... values) 方法:

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

它和 postResult(Result result) 方法是一样的,发送一个消息,就不在多说了,回过头看一下就知道了。

以上就是 AsyncTask 的主要执行过程。

相关文章

《Android 中的 HandlerThread 类详解》
《Android 中的 IntentService 类详解》
《Android中的Handler机制分析(一) Handler和Message分析》
《Android中的Handler机制分析(二) MessageQueue分析》
《Android中的Handler机制分析(三) Looper分析和Handler其他知识》

更多相关文章

  1. Android(安卓)Handler解析
  2. Android-使用HttpURLConnection实现多线程下载
  3. Android(安卓)通过listView+RadioButton实现列表的单选功能
  4. Android通知栏-Notification(通知消息)
  5. Unity和Android相互通信
  6. 美团热修复 Robust 方案接入(一)
  7. Android中的属性动画理解
  8. Android基础知识(2)—事件处理
  9. android data binding

随机推荐

  1. labview使用DSN与数据库的连接包括access
  2. 【文档】五、Mysql Binlog事件结构
  3. g++ 连接 mysql 编译报错 /usr/bin/ld: c
  4. Mysql 查看及设置事物隔离级别
  5. mysql学习之路_外键
  6. 如何用mysql或Navicat实现流水号的插入
  7. 远程服务器CentOS7安装MySQL并用本地Navi
  8. 在mac中配置apache+php5.3+mysql的环境,修
  9. 如何在mysql中的两个值之间插入一个新值
  10. 主义通过扩展来破坏对实体的查询