[TOC]
关于 Android 源码分析,引用郭霖老师博客的一段话:
> 简单概括就是八个字:抽丝剥茧、点到即止。应该认准一个功能点,然后去分析这个功能点是如何实现的。但只要去追寻主体的实现逻辑即可,千万不要试图去搞懂每一行代码都是什么意思,那样很容易会陷入到思维黑洞当中,而且越陷越深。因为这些庞大的系统都不是由一个人写出来的,每一行代码都想搞明白,就会感觉自己是在盲人摸象,永远也研究不透。如果只是去分析主体的实现逻辑,那么就有比较明确的目的性,这样阅读源码会更加轻松,也更加有成效。
本文不是原创,是在阅读了互联网上各位大神关于 AsyncTask 源码分析的文章后,自己对于 AsyncTask 进行的一遍分析,虽不是原创,但自己顺着思路捋一遍,并敲下本文后,感觉对于 AsyncTask 的用法以及原理的理解更加深刻了。
本文参考资料:
[Android中AsyncTask使用详解–孙群](http://blog.csdn.net/iispring/article/details/50639090)
[Android异步任务AsyncTask的使用与原理分析–开心阳](http://blog.csdn.net/shakespeare001/article/details/51720548)
[Android AsyncTask完全解析,带你从源码的角度彻底理解–郭霖](http://blog.csdn.net/guolin_blog/article/details/11711405)
AsyncTask 的基础使用
AsyncTask 是一个抽象类,必须写一个子类继承它,在子类中完成异步操作。AsyncTask 抽象类指定了3个泛型类型参数:
```java
public abstract class AsyncTask<Params, Progress, Result> {
...
}
```
三个泛型类型参数的含义如下:
* Params:开始异步任务执行时传入的参数类型,即 doInBackground()方法中的参数类型;
* Progress:异步任务执行过程中,返回进度值的类型,即在 doInBackground 中调用 publishProgress()时传入的参数类型;
* Result:异步任务执行完成后,返回的结果类型,即 doInBackground()方法的返回值类型;
AsyncTask 的回调方法包括:
* onPreExecute():在执行后台操作之前调用,运行在主线程中;
* doInBackground():核心方法,执行后台操作的方法,必须实现的一个方法,运行在子线程中;
* onPostExecute():后台操作完成后调用,运行在主线程中;
* onProgressUpdate():在下载操作 doInBackground()中调用 publishProgress()时的回调方法,用于更新下载进度,运行在主线程中;
# 使用注意事项
* 对于一个 AsyncTack 的实例,只能执行一次 execute 方法,在该实例上第二次执行 execute 方法时就会抛出异常。
* AsyncTask 在最早的版本中用一个单一的后台线程串行执行多个 AsyncTask 实例的任务,从 Android 1.6(DONUT)开始,AsyncTask 用线程池并行执行异步任务,但是从Android 3.0(HONEYCOMB)开始为了避免并行执行导致的常见错误,AsyncTask 又开始默认用单线程作为工作线程处理多个任务。
从Android 3.0开始 AsyncTask 增加了 executeOnExecutor 方法,用该方法可以让 AsyncTask 并行处理任务,该方法的方法签名如下所示:
```java
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params)
```
第一个参数表示 exec 是一个 Executor 对象,为了让 AsyncTask 并行处理任务,通常情况下我们此处传入 AsyncTask.THREAD_POOL_EXECUTOR 即可,AsyncTask.THREAD_POOL_EXECUTOR 是 AsyncTask 中内置的一个线程池对象,当然我们也可以传入我们自己实例化的线程池对象。第二个参数 params 表示的是要执行的任务的参数。
# 整体流程
1、首先调用 AsyncTask 的构造方法,构造时对 Handler、WorkerRunnable(Callable) 和 FutureTask 进行初始化
2、然后调用 AsyncTask 的 execute 方法(可以手动设置 Executor,不设置则使用系统默认的 SerialExecutor)
3、首先判断当前 AsyncTask 状态,正在运行或者已经运行过就退出
4、调用 onPreExecute 执行准备工作
5、由 Executor 调用 FutureTask 的 run 方法,在 WorkerRunnable 中执行了 doInBackground
6、依旧是在 WorkerRunnable 中,调用 postResult,将执行结果通过 Handler 发送给主线程;调用 publishProgress 时,也是通过 Handler 将消息发送到主线程的消息队列中
# 源码解析
开始一个 AsyncTask 任务很简单,只要执行 new AsyncTask().execute()方法即可。我们的源码分析也从这里开始。
首先来看 AsyncTask 的构造函数:
```java
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
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<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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
```
可以看到,在构造函数中,初始化了两个变量 mWorker 和 mFuture。首先看看 AsyncTask 的 execute()方法。
```java
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
```
很简单,在主线程进行调用,返回 executeOnExecutor(sDefaultExecutor, params)方法的值,那么我们看看这个方法:
```java
@MainThread
public final AsyncTask<Params, Progress, Result> 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;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
```
可以看到,首先对 AsyncTask 的状态进行了判断,当 AysncTask 的状态是 RUNNING 和 FINISHED 时,会抛出异常,这也是为什么一个任务实例只能被启动一次的原因。executeOnExecutor()方法传入两个参数,一个是 Executor,一个是 Params。Params 就是我们执行 doInBackground 中的参数类型。那么 Executor 呢,可以在上一段代码看到,传递来的参数是 sDefaultExecutor,它的初始化如下:
```java
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
```
在 executeOnExecutor 方法中我们可以看到,先执行了 onPreExecute()方法,是在主线程。接着执行 exec.execute(mFuture),那么 doInBackground()方法应该就和它有关系了。接下来看看 SerialExecutor 类的 execute 方法,源码如下:
```java
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
```
可以看到,其中执行了参数 Runnable 的 run() 方法,这个 Runnable 就是传进来的 mFuture。那么看看 FutureTask 的 run()方法:
```java
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> 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 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);
}
}
```
在 run() 方法中执行了 Callable 的 call()方法,callable 又是谁呢,callable 就是在 FutureTask 初始化时传进来的 mWorker。说明调用的是 mWorker 的 call()方法。去看看:
```java
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;
}
```
在这段代码中,终于看到我们的 doInBackground()方法,此时依旧是在工作线程中运行。紧接着是 postResult(result),这其中又做了什么呢:
```java
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
```
查看源码得知,getHandler()返回的是 InternalHandler 的实例对象,那么就要去看看 InternalHandler 的 handleMessage()方法了。
```java
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;
}
}
```
可以看到,当 msg 的 what 值为 MESSAGE_POST_RESULT 时,代表工作线程的任务执行完成,执行 finish()方法。what 值为 MESSAGE_POST_PROGRESS 时,执行 onProgressUpdate(),也就是调用 publishProgress()时的回调方法。看一看 finish() 方法:
```java
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
```
当前任务被取消时,调用 onCancelled()方法,否则调用 onPostExecute()方法。最后看一下 publishProgress()的源码:
```java
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
```
至此,主要的源码就看完了,可以看到 AsyncTask 是对 Handler、Message 机制的一种封装,使得我们的调用更加简洁。
- 导读
- Java知识
- Java基本程序设计结构
- 【基础知识】Java基础
- 【源码分析】Okio
- 【源码分析】深入理解i++和++i
- 【专题分析】JVM与GC
- 【面试清单】Java基本程序设计结构
- 对象与类
- 【基础知识】对象与类
- 【专题分析】Java类加载过程
- 【面试清单】对象与类
- 泛型
- 【基础知识】泛型
- 【面试清单】泛型
- 集合
- 【基础知识】集合
- 【源码分析】SparseArray
- 【面试清单】集合
- 多线程
- 【基础知识】多线程
- 【源码分析】ThreadPoolExecutor源码分析
- 【专题分析】volatile关键字
- 【面试清单】多线程
- Java新特性
- 【专题分析】Lambda表达式
- 【专题分析】注解
- 【面试清单】Java新特性
- Effective Java笔记
- Android知识
- Activity
- 【基础知识】Activity
- 【专题分析】运行时权限
- 【专题分析】使用Intent打开三方应用
- 【源码分析】Activity的工作过程
- 【面试清单】Activity
- 架构组件
- 【专题分析】MVC、MVP与MVVM
- 【专题分析】数据绑定
- 【面试清单】架构组件
- 界面
- 【专题分析】自定义View
- 【专题分析】ImageView的ScaleType属性
- 【专题分析】ConstraintLayout 使用
- 【专题分析】搞懂点九图
- 【专题分析】Adapter
- 【源码分析】LayoutInflater
- 【源码分析】ViewStub
- 【源码分析】View三大流程
- 【源码分析】触摸事件分发机制
- 【源码分析】按键事件分发机制
- 【源码分析】Android窗口机制
- 【面试清单】界面
- 动画和过渡
- 【基础知识】动画和过渡
- 【面试清单】动画和过渡
- 图片和图形
- 【专题分析】图片加载
- 【面试清单】图片和图形
- 后台任务
- 应用数据和文件
- 基于网络的内容
- 多线程与多进程
- 【基础知识】多线程与多进程
- 【源码分析】Handler
- 【源码分析】AsyncTask
- 【专题分析】Service
- 【源码分析】Parcelable
- 【专题分析】Binder
- 【源码分析】Messenger
- 【面试清单】多线程与多进程
- 应用优化
- 【专题分析】布局优化
- 【专题分析】绘制优化
- 【专题分析】内存优化
- 【专题分析】启动优化
- 【专题分析】电池优化
- 【专题分析】包大小优化
- 【面试清单】应用优化
- Android新特性
- 【专题分析】状态栏、ActionBar和导航栏
- 【专题分析】应用图标、通知栏适配
- 【专题分析】Android新版本重要变更
- 【专题分析】唯一标识符的最佳做法
- 开源库源码分析
- 【源码分析】BaseRecyclerViewAdapterHelper
- 【源码分析】ButterKnife
- 【源码分析】Dagger2
- 【源码分析】EventBus3(一)
- 【源码分析】EventBus3(二)
- 【源码分析】Glide
- 【源码分析】OkHttp
- 【源码分析】Retrofit
- 其他知识
- Flutter
- 原生开发与跨平台开发
- 整体归纳
- 状态及状态管理
- 零碎知识点
- 添加Flutter到现有应用
- Git知识
- Git命令
- .gitignore文件
- 设计模式
- 创建型模式
- 结构型模式
- 行为型模式
- RxJava
- 基础
- Linux知识
- 环境变量
- Linux命令
- ADB命令
- 算法
- 常见数据结构及实现
- 数组
- 排序算法
- 链表
- 二叉树
- 栈和队列
- 算法时间复杂度
- 常见算法思想
- 其他技术
- 正则表达式
- 编码格式
- HTTP与HTTPS
- 【面试清单】其他知识
- 开发归纳
- Android零碎问题
- 其他零碎问题
- 开发思路