AsyncTask源码详解
AsyncTask是Android提供的异步执行任务的工具,上层使用了串行任务调度器保证单任务执行,底层使用了线程池实现,另外使用了FutureTask的特性,提供了终止任务的方法。
一、AsyncTask使用方法
1.自定义AsyncTask
继承AsyncTask,重写回调方法
写一个可以计算斐波纳契数列和的异步任务,耗时久一点
public class FibonacciTask extends AsyncTask<Integer, Float, Integer> {
private static final String TAG = "FibonacciTask";
@Override
protected Integer doInBackground(Integer... integers) {
int sum = 0, length = integers.length;
for(int i = 0 ; i < length; i++) {
sum += fn(integers[i]);
publishProgress(((float)(i + 1) / (float)length) * 100);
Log.d(TAG, "doInBackground " + printThread());
}
return sum;
}
@Override
protected void onPreExecute() {
// super.onPreExecute(); 空方法
// 这里可以做一些初始化,打印一下调用就好
Log.d(TAG, "onPreExecute" + printThread());
printThread();
}
@Override
protected void onPostExecute(Integer integer) {
// super.onPostExecute(integer); 空方法
// 打印一下结果
Log.d(TAG, "onPostExecute: " + integer + printThread());
}
@Override
protected void onProgressUpdate(Float... values) {
// super.onProgressUpdate(values); 空方法
// 打印一下进度
Log.d(TAG, "onProgressUpdate: " + values[0] + printThread());
}
@Override
protected void onCancelled(Integer integer) {
// 父类 调了onCancelled(),onCancelled()为空方法
// super.onCancelled(integer);
// 打印一下调用
Log.d(TAG, "onCancelled("+ integer +")" + printThread());
}
@Override
protected void onCancelled() {
// super.onCancelled(); 空方法
// 打印一下调用
Log.d(TAG, "onCancelled()" + printThread());
}
private int fn(int n) {
if(n == 1 || n == 2) {
return 1;
}
return fn(n - 1) + fn(n - 2);
}
private String printThread() {
return " threadId:" + Thread.currentThread().getId();
}
}
2.创建对象,执行任务
创建任务对象,执行任务
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: threadId:" + Thread.currentThread().getId());
// 创建一个异步任务对象
final FibonacciTask task = new FibonacciTask();
// 开始执行
task.execute(10, 11, 15, 30, 40);
Button button = findViewById(R.id.cancel);
// 点击取消任务
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 这个boolean参数表示是否中断正在执行的任务
task.cancel(true);
}
});
}
}
结果如下:
2020-05-19 23:18:59.862 2876-2876/? D/MainActivity: onCreate: threadId:2
2020-05-19 23:18:59.862 2876-2876/? D/FibonacciTask: onPreExecute threadId:2
2020-05-19 23:19:01.416 2876-2903/comlscag.learn D/FibonacciTask: doInBackground threadId:200
2020-05-19 23:19:01.416 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 20.0 threadId:2
2020-05-19 23:19:03.854 2876-2903/comlscag.learn D/FibonacciTask: doInBackground threadId:200
2020-05-19 23:19:03.854 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 40.0 threadId:2
2020-05-19 23:19:07.748 2876-2903/comlscag.learn D/FibonacciTask: doInBackground threadId:200
2020-05-19 23:19:07.748 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 60.000004 threadId:2
2020-05-19 23:19:14.033 2876-2903/comlscag.learn D/FibonacciTask: doInBackground threadId:200
2020-05-19 23:19:14.033 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 80.0 threadId:2
2020-05-19 23:19:24.213 2876-2903/comlscag.learn D/FibonacciTask: doInBackground threadId:200
2020-05-19 23:19:24.213 2876-2876/comlscag.learn D/FibonacciTask: onProgressUpdate: 100.0 threadId:2
2020-05-19 23:19:24.213 2876-2876/comlscag.learn D/FibonacciTask: onPostExecute: 1670731762 threadId:2
可以看到除了doInBackground以外的方法都是在主线程执行的。
二、Async源码详解
2.1 创建任务
2.1.1 构造方法
public AsyncTask() {
// 调用AsyncTask(@Nullable Looper callbackLooper),传入Looper为空
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
* 必须在主线程调用?为什么?
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
// 默认的构造方法looper传进来是null,这里会调getMainHandler() 获取handler,
// 如果反射传进来了指定的looper,并且不是主线程的looper,则会将handler指向对应线程(原理和HandlerThread一样)
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// 创建一个WorkerRunnable对象,它是任务的实际执行者,详见2.2.4
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;
}
};
// 创建一个FutureTask对象,传入刚才创建的worker,
// 可以看到这里重写了done方法,FutureTask的介绍详见2.2.5
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对象,mWorker是任务的实际执行者,mFuture提供了对任务管理(触发、调度、取消、传递结果)等功能。
2.2 执行任务
2.2.1 串行执行器执行任务
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// sDefaultExecutor详见2.2.2
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 执行过execute的异步任务对象无法再执行第二次
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();
// 给worker设置参数
mWorker.mParams = params;
// 串行执行器执行任务
exec.execute(mFuture);
return this;
}
2.2.2 串行控制器
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
// 维护了一个任务队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
// 执行方法,将任务入队,如果当前没有执行任务,就开始调用线程池执行,否则等当前任务执行完成才执行下一个任务,典型的串行控制器,多个异步任务执行execute时是串行执行的
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);
}
}
}
2.2.3 线程池执行器
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 核心线程数:可用cpu核心数 <= 3为2个;可用cpu核心数 >= 4为4个
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
// 线程池最大容量:cpu核心数*2 +1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
// 非核心线程最大存活时间:30秒
private static final int KEEP_ALIVE_SECONDS = 30;
// 线程工厂:给每个线程按顺序指定了name
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;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
可以看到线程池是支持多个任务并行执行的,但由于串行控制器的存在,实际上多个异步任务是串行执行的,当然,可以通过反射hook掉串行执行器,实现并行的异步任务。
串行控制器会依次将任务队列中的任务交给线程池执行,执行的任务正是创建AsyncTask实例时构造的mFuture对象,mFuture对象又持有了WorkRunnable对象mWorker,接下来看看这两个对象是如何工作的。
2.2.4 WorkRunnable 和 Callable
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
public interface Callable<V> {
V call() throws Exception;
}
WorkerRunnable是AsyncTask的静态内部类,实现了Callable接口
根据1.1中创建的匿名类可以看到WorkerRunnable会持有doInBackground的参数mParams,
并且返回处理结果result
2.2.5 FutureTask
FutureTask间接实现了Runnable接口,在被线程池调度时会执行run方法。
// 异步任务中创建mFuture的构造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
// FutureTask中done是个空方法
protected void done() { }
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);
}
}
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
其run方法判断了任务状态,如果不是新任务不会被执行,同时用CAS的方法记录了当前执行任务线程到FutureTask的runner字段,接着调用了mWorker的run方法真正执行任务,如果任务被成功执行,则会调set方法修改当前任务状态,并调finishCompletion结束任务。
2.2.6 任务取消
最后看一下AsyncTask的取消过程
// AsyncTask.cancel
public final boolean cancel(boolean mayInterruptIfRunning) {
// 设置取消状态,并执行mFuture的cancel方法
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
// FutureTask.cancel
public boolean cancel(boolean mayInterruptIfRunning) {
// 判断并修改任务状态,如果设置cancel是允许中断当前执行任务的,则会中断正在执行的线程
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
// 最终调用finishCompletion结束任务
finishCompletion();
}
return true;
}
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
// 可以看到这里调了done方法,可以回到2.1.1的构造方法中看到,done方法会将已经执行的结果传递出去
done();
callable = null; // to reduce footprint
}
AsyncTask的任务取消操作是基于FutureTask的取消操作执行的,提供了中断当前任务\不中断当前任务,两种取消方法,并且会在取消时返回已执行结果。