AsyncTask 总结

AsyncTask 的作用

AsyncTask 允许对用户界面执行异步操作。 它会先阻塞工作线程中的操作,然后在 UI 线程中发布结果,而无需您亲自处理线程和/或处理程序。

AsyncTask 基于异步消息处理机制进行实现,通过 AsyncTask 能够很简单的从子线程切换至主线程。

AsyncTask 的基本使用

  1. 由于 AsyncTask 是抽象类,所以首先需要创建一个继承它的子类。

    1
    public class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> 

    其中可以为 AsyncTask 指定三个泛型参数
    • Params:执行 Task 时传递的参数,在后台任务中使用,这里指定为 Void
    • Progress:指定进度单位,这里指定为 Integer
    • Result:执行完任务后返回的类型,这里指定为 Boolean
  2. 重写 AsyncTask 的一些方法,主要是下面四个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    @Override
    protected void onPreExecute() {
    progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(Void... voids) {
    while (true) {
    int percent = doDownload();
    publishProgress(percent);
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    return false;
    }
    if (percent >= 100) {
    break;
    }

    }
    return true;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
    progressDialog.setMessage("Downloaded " + values[0] + "%");
    }

    @Override
    protected void onPostExecute(Boolean result) {
    progressDialog.dismiss();

    if (result) {
    Toast.makeText(MainActivity.getCurrentContext(),
    "Download Succeeded", Toast.LENGTH_LONG).show();
    } else {
    Toast.makeText(MainActivity.getCurrentContext(),
    "Download Failed", Toast.LENGTH_LONG).show();
    }
    }
    • onPreExecute():任务执行之前在 UI 线程当中进行调用,通常用于进行一些界面的初始化工作,譬如显示一个进度条。
    • doInBackground(Params...):必须实现的方法,在 onPreExecute() 方法执行完毕之后运行在子线程上,通常用于执行耗时任务,Params 参数将会传递至该方法。执行完任务之后将会通过 return 语句返回执行结果,如果 Result 设定为 Void 则可以不进行返回。同时在该方法中可以通过 publishProgress(Progress...) 方法对任务执行进度进行反馈。
    • onProgressUpdate(Progress...):publishProgress(Progress...) 被调用之后执行在 UI 线程当中,在该方法中可以展示任务执行的进度及对进度进行更新,譬如可以对进度条进行动画处理。
    • onPostExecute(Result):任务执行完之后的返回结果将会传递至该方法,可以利用返回的结果进行一些 UI 操作,譬如提醒任务执行的结果,该方法运行在 UI 线程中。

AsyncTask 源码浅解

执行过程图

执行过程

  1. 首先通过调用 execute(Params... params) 方法执行任务 内部执行了 executeOnExecutor(sDefaultExecutor, params),sDefaultExecutor 是内部定义的 SerialExecutor 类的对象,主要的方法是 execute(final Runnable r) 用于启动一个线程。
  2. executeOnExecutor(Executor exec, Params... params) 作为第一步中执行的方法,首先会判断任务的运行状态,如果是 PENDING 则表明没有运行,然后便会执行 onPreExecute() 方法,之后将 params 传递给 mWorker 对象,mWorker 是一个实现了 Callable 接口的 WorkerRunnable 对象,最后调用 exec.execute(mFuture) 去启动线程。其中 mWorker 和 mFuture 对象在构造函数中完成了初始化过程。mFuture 是一个实现了 RunnableFuture 接口的 FutureTask 对象,FutureTask 的 run() 方法将会调用 Callable 接口的 call() 方法。也即是说 exec.execute(mFuture) 调用了 mFuture 的 run() 方法从而调用了 mWorker 的 call() 方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    //execute 的执行过程
    exec.execute(mFuture);
    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);
    }
    }
    }

    //mFuture 调用 mWorker.call() 的过程
    mFuture = new FutureTask<Result>(mWorker)
    //将 mWorker 保存至 mFuture 的 callable
    public FutureTask(Callable<V> callable) {
    if (callable == null)
    throw new NullPointerException();
    this.callable = callable;
    this.state = NEW; // ensure visibility of callable
    }

    public void run() {
    if (state != NEW ||
    !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
    return;
    try {
    //callable 赋值给 c
    Callable<V> c = callable;
    if (c != null && state == NEW) {
    V result;
    boolean ran;
    try {
    //相当于调用 mWorker 的 call 方法
    result = c.call();
    ran = true;
    } catch (Throwable ex) {
    result = null;
    ran = false;
    setException(ex);
    }
    if (ran)
    set(result);
    }
    } finally {
    // runner must be non-null until state is settled to
    // prevent concurrent calls to run()
    runner = null;
    // state must be re-read after nulling runner to prevent
    // leaked interrupts
    int s = state;
    if (s >= INTERRUPTING)
    handlePossibleCancellationInterrupt(s);
    }
    }

  3. 执行完上述两步之后 mWorker.call() 得到了调用,任务开始启动。 在 call() 方法中调用了 doInBackground(mParams) 并将结果保存在 result 变量当中,然后在 postResult(result) 中通过 getHandler() 获取到 InternalHandler 对象,通过 obtainMessage() 方法将结果发送出去,之后在 handleMessage(Message msg) 中调用了 finish() 方法。finish() 方法中最终调用了 onPostExecute(result) 方法。 如果在 doInBackground(mParams) 调用了 publishProgress(Progress... values),则在 publishProgress(Progress... values) 中也会通过 getHandler() 发送 Message,然后在 handleMessage(Message msg) 中调用 onProgressUpdate(Progress... values) 方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
    new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
    }

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

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

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