[Android] AsyncTask源码解析

常用例子

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

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/

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
各种安全相关思维导图整理收集。渗透步骤,web安全,CTF,业务安全,人工智能,区块链安全,数据安全,安全开发,无线安全,社会工程学,二进制安全,移动安全,红蓝对抗,运维安全,风控安全,linux安全.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值