Android源码解析——AsyncTask
来源:互联网 发布:淘宝女装店铺策划书 编辑:程序博客网 时间:2024/04/29 16:54
转载于 http://blog.csdn.net/maosidiaoxian/article/details/51291106
简介
AsyncTask 在Android API 3引入,是为了使UI线程能被正确和容易地使用。它允许你在后台进行一些操作,并且把结果带到UI线程中,而不用自己去操纵Thread或Handler。它被设计为一个围绕着Thread和Handler的辅助类,而不是一种通用的线程框架。在API文档中,建议你把它用于一些耗时比较短(大部分情况下只有几秒)的操作,如果你需要让线程长期运行,则强烈推荐使用java.util.concurrent
里的API来处理。
如上所述,一个异步任务是在后台中进行计算,并把结果带到UI线程中。在这里,一个异步任务定义了三个泛型类型(Params
,Progress
和Result
),以及四个步骤(onPreExecute
,doInBackground
,onProgressUpdate
和onPostExecute
)。
用法
在官方文档中,以下载文件为例,提供了示例代码,先定义一个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"); } }然后通过调用它的实例的execute(Params…)方法来执行。
new DownloadFilesTask().execute(url1, url2, url3);
源码解析
下面来看一下这个类的代码,本文以android-23版本的代码为例。
成员变量
首先是这个类的成员变量。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
其中WorkerRunnable是对Callable的封装,包装了一个异步任务的参数。Status是定义的表示异步任务状态的枚举类型,共有三个状态,分别是PENDING(待绪),RUNNING(正在运行),FINISHED(已经完成)。
成员方法
再来看API中提供的所有成员方法:
我们从上面的示例代码中一个异步任务的执行开始,逐步跟踪它的执行过程。
- 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
从上面的代码可以看出,一个异步任务不能被重复执行,否则将会抛异常。当执行它的时候,状态会被设为
Status.RUNNING
,同时会调用onPreExecute()
方法,然后把传进来的参数赋值到所封装的worker中,再调用一个Executor的execute
方法。onPreExecute
是前面所述的一个异步任务的四个步骤之一,它是用在UI线程中的。所以我们要在UI线程中调用execute
方法,才能使其在UI线程中被调用。
上面所用的Executor为sDefaultExecutor
,我们来看一下它的定义:- 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
可以看到,默认的Executor是串行处理后台任务的。然而,需要注意的是,AsyncTask在Android API 11之前曾经被设计为并行的,所以如果你在API 11之后需要并行地执行任务,可以直接调用
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)
。对此,谷歌在support库提供了封装这个操作的兼容类AsyncTaskCompat
,因此你也可以直接调用AsyncTaskCompat.executeParallel(task, params)
来使它能够被并行执行。那么,一个异步任务是如何完成各个步骤的依次调用的?我们再回到它的构造方法来:
- 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
当
mFuture
被Executor执行时,会执行其mWorker
。它在调用的时候,先把mTaskInvoked
设置为true表示已调用,设置线程优先级,然后才执行doInBackground()
方法,并执行postResult
发送其返回的结果。postResult
代码如下:- 1
- 2
- 3
- 4
- 5
- 6
- 7
如果在执行
doInBackground
过程中发生异常的话,而上面的代码可能就不会被执行,所以通过重写FutureTask
的done
方法,在里面调用postResultIfNotInvoked
,以确保任务执行完成的步骤被调用。
在前面的代码中,getHandler()
返回的是一个InternalHandler
单例,该类代码如下:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
也就是消息被绑到主线程的消息队列了。同样,更新进度也是通过这种方法来把消息发送到主线程的消息队列中去执行:
- 1
- 2
- 3
- 4
- 5
- 6
而在任务完成的方法中,先判断任务是否被取消,被取消的话则回调被取消的方法,否则回调
onPostExecute
,最终把任务的状态设为已结束。源码如下:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
以上就是AsyncTask对后台任务及UI线程之间的交互所做的封装。
AsyncTask还提供了取消任务以及等待任务执行的结果的几个API,它们原是FutureTask所提供的特性,所以也只是通过调用mFuture的对应方法,这里不再赘述。总结
通过上面的代码可以总结出几条:
- AsyncTask在不同的版本可能是串行执行的,也可能是并行执行的。
- 如果要确保任务被并行执行,可以通过support库的AsyncTaskCompat来执行。
- 一个AsyncTask只能被执行一次,不能被多次执行。
- 取消一个AsyncTask,可以设置是否允许中断它。
- 如果取消了一个AsyncTask,则不会再回调
onProgressUpdate
。 - 当一个任务完成时,如果它已经被取消,则回调
onCancelled
方法,否则回调onPostExecute
方法。
版权声明:本文为博主原创文章,未经博主允许不得转载。博主项目:https://github.com/msdx/status-bar-compat
- Android源码解析——AsyncTask
- Android源码解析——AsyncTask
- Android AsyncTask源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android:AsyncTask源码解析
- Android AsyncTask源码解析
- [Android] AsyncTask源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Rocket.Chat - REST API
- 使用变量全局替换字符串,替换字符串中出现的文字
- gulp教程之gulp-less
- 动态规划-最长递增子序列
- java 四舍五入取整
- Android源码解析——AsyncTask
- C#四路继电器usb转com口编程
- wap页活动倒计时
- $.each的用法
- 怎样创建任务计划程序
- 【面向代码】学习 Deep Learning(一)Neural Network
- 易语言 获取系统目录
- 【Day20】数据库中的事务是什么 ?
- 对象内存分配策略