[Android] AsyncTask源码解析

原创 2015年11月18日 13:11:31

常用例子

本文依照以下常用例子展开:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        for (int i = 0; i < count; i++) {
            totalSize += Downloader.downloadFile(urls[i]);
            publishProgress((int) ((i / (float) count) * 100));
            // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        return totalSize;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result) {
        showDialog("Downloaded " + result + " bytes");
    }
}

new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask的使用方法太常见了,这里不做详述。值得注意的是AsyncTask有以下用法:

DownloadFilesTask mDownloadFilesTask = new DownloadFilesTask().execute(url1, url2, url3);
Long result = mDownloadFilesTask.get(); // 如果doInBackground还没执行完毕,那么堵塞直到它返回结果为止。

可以通过get()方法来获得AsyncTask的运行结果,这是通过java.util.concurrent的FutureTask类来完成的。AsyncTask类依赖于java.util.concurrent,task的执行和调度都由FutureTask、Executor、LinkedBlockingQueue等类来完成,下文会对其展开介绍。

源码解析

AsyncTask的状态

AsyncTask有三种状态:

public enum Status {
    PENDING,
    RUNNING,
    FINISHED,
}

对象初始化完毕后为PENDING状态,execute()被执行时转变成RUNNING状态,onPostExecute执行后变成FINISHED状态。execute()方法仅可以在task为PENDING状态下调用,否则会抛出IllegalStateException

AsyncTask的初始化

AsyncTask有很多静态属性:

public abstract class AsyncTask<Params, Progress, Result> {
    ...

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    ...

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    private static InternalHandler sHandler;

    ...

    private static class SerialExecutor implements Executor {
        ...
    }

其中:

sThreadFactory:供THREAD_POOL_EXECUTOR使用。为每个thread设定自增的name。

sPoolWorkQueue:供THREAD_POOL_EXECUTOR使用。

THREAD_POOL_EXECUTOR:供SerialExecutor使用,task真正执行的场所。

SERIAL_EXECUTOR:默认executor的实现,下文会对其详述。

sHandler:初始化时注入主线程的looper,接收MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS消息。

其中SerialExecutor的实现如下所示:

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

代码逻辑如下所示:

  1. 当SerialExecutor对象的execute(runnable)执行时,首先会将runnable对象包装一下,然后放到一个FIFO的队列mTasks当中。如果是首次执行,那么scheduleNext()方法会被调用。
  2. 在scheduleNext()方法中,mTasks中的runnable被取出并赋给mActive变量,然后将mActive放到THREAD_POOL_EXECUTOR中执行。
  3. 在THREAD_POOL_EXECUTOR中调用run()方法,然后再次调用scheduleNext()方法取出下一个runnable。

接下来看一下AsyncTask的初始化方法:

public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            return postResult(doInBackground(mParams));
        }
    };

    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 occured while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

WorkerRunnable的源码如下所示:

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

可以看到WorkerRunnable继承于Callable,因此可以放到Executor中执行。因此mWorker这个匿名类的call方法会在Executor中调用。
首先将mTaskInvoked设置为true。mTaskInvoked用于检查当前的mWorker是否已经被执行(有可能还没执行就cancel了)。然后设置一下线程优先级,最后调用postResult()方法向sHandler发送MESSAGE_POST_RESULT消息。

接下来看mFuture。mFuture是一个FutureTask对象,可以通过调用mFuture.get()来堵塞式地等待task的执行结果,详情可以参考这里。done()方法会在mWorker结束(无论是cancel还是正常finish)时调用。其中postResultIfNotInvoked()源码如下所示:

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {
        postResult(result);
    }
}

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

private static class InternalHandler extends Handler {
    public InternalHandler() {
        super(Looper.getMainLooper());
    }

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

如果当前mWorker没有被执行过,则执行postResult()方法。这里保证了无论mWorker是否正常结束,主线程的回调依然会正常执行。

AsyncTask的执行

通过类似调用new DownloadFilesTask().execute(url1, url2, url3);可以执行一个AsyncTask。execute方法的源码如下所示:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {

    //1. 检查和设置task的状态
    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;

    //2. 回调api
    onPreExecute();

    //3. 设置params和在sDefaultExecutor上执行mFuture
    mWorker.mParams = params;
    exec.execute(mFuture);

    return this;
}

代码逻辑见注释。结合前文对mFuture和mWorker的讲解,可以画出AsyncTask的执行流程图:

+----------+          +--------+          +---------+          +---------------+      +--------------------+   +------------+     +--------------+
|MainThread|          |sHandler|          |AsyncTask|          |SERIAL_EXECUTOR|      |THREAD_POOL_EXECUTOR|   | FutureTask |     |WorkerRunnable|
+----+-----+          +---+----+          +----+----+          +-------+-------+      +----------+---------+   +------+-----+     +-------+------+
     |                    |        new         |                       |                         |                    |                   |
     +---------------------------------------> |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    +----------+            |                         |                    |                   |
     |                    |       set mWorker and mFuture |            |                         |                    |                   |
     |                    |                    |          |            |                         |                    |                   |
     |                    |                    | <--------+            |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |         execute(Params... params)       |                       |                         |                    |                   |
     +---------------------------------------> |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |  onPreExecute()    |                       |                         |                    |                   |
     | <---------------------------------------+  exec.execute(mFuture)|                         |                    |                   |
     |                    |                    +---------------------> |   scheduleNext()        |                    |                   |
     |                    |                    |                       +------+                  |                    |                   |
     |                    |                    |                       |      |                  |                    |                   |
     |                    |                    |                       |      |                  |                    |                   |
     |                    |                    |                       | <----+                  |                    |                   |
     |                    |                    |                       |     execute(mActive)    |                    |                   |
     |                    |                    |                       +-----------------------> |      run()         |                   |
     |                    |                    |                       |                         +------------------> |      call()       |
     |                    |                    |                       |                         |                    +-----------------> |
     |                    |                    |    doInBackground()   |                         |                    |                   |
     |                    |                    | <----------------------------------------------------------------------------------------+
     |                    | MESSAGE_POST_RESULT|                       |                         |                    |                   |
     |                    | <-------------------------------------------------------------------------------------------------------------+
     |                    |   finish()         |                       |                         |                    |      done()       |
     |                    +------------------> |                       |                         |                    | <-----------------+
     |  onPostExecute(result)                  |                       |                         |                    |                   |
     | <---------------------------------------+                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     |                    |                    |                       |                         |                    |                   |
     +                    +                    +                       +                         +                    +                   +

查看原文:http://legendmohe.net/2015/11/18/android-asynctask%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90/

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Android AsyncTask 源码解析

  • 2014-08-16 17:45
  • 1.37MB
  • 下载

Android AsyncTask 源码解析

Android AsyncTask 源码解析 分类: 【android 进阶之路】 【Android 源码解析】2014-08-18 09:10 2540人阅读 评论(12) 收藏 举报...
  • anlun
  • anlun
  • 2014-11-18 23:49
  • 353

Android AsyncTask完全解析,带你从源码的角度彻底理解

版权声明:本文出自郭霖的博客,转载必须注明出处。 目录(?)[+] 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/1...

Android AsyncTask 源码解析

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38614699,本文出自:【张鸿洋的博客】 1、概述 相信大家对AsyncTa...
  • wy819
  • wy819
  • 2016-05-06 14:49
  • 99

Android AsyncTask完全解析,带你从源码的角度彻底理解

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线...

Android AsyncTask 源码解析(一)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38614699,本文出自:【张鸿洋的博客】 1、概述 相信大家对Asy...

(4.1.4)Android AsyncTask 源码解析

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38614699,本文出自:【张鸿洋的博客】 1、概述 相信大家对AsyncTa...

Android AsyncTask完全解析,带你从源码的角度彻底理解

我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制。之前我也写过了一篇文章从源码层面分

Android之AsyncTask源码解析

注释都写在代码里了,直接看代码吧:/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the A...

Android AsyncTask完全解析,带你从源码的角度彻底理解

出处:http://blog.csdn.net/guolin_blog/article/details/11711405   我们都知道,Android UI是线程不安全的,如果想要在子线程里进行...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)