AsyncTask源码学习
AsyncTask的实现原理是通过Java中的线程池来的。
一、重要属性
AsyncTask中又三个线程池的成员变量:
- THREAD_POOL_EXECUTOR:这是一个public修饰的静态成员,是Executor常量
- SERIAL_EXECUTOR:这是一个public修饰的静态成员,是Executor常量,只不过在定义的同时直接初始化为了内部类SerialExecutor对象,该类实现类任务的按序执行
- sDefaultExecutor:这是一个private修饰的静态成员,volatile修饰,而且默认值为SERIAL_EXECUTOR
关于线程池配置的一些参数:
- CORE_POOL_SIZE:核心池的大小,值为Math.max(2, Math.min(CPU_COUNT - 1, 4))
- MAXIMUM_POOL_SIZE:线程池最大容量,值为CPU_COUNT * 2 + 1
- KEEP_ALIVE_SECONDS:空闲线程的存活时间,值为30s
- sTreadFactory:生成Thread对象的工厂,唯一干的事情就是记录线程创建的数目,并且按照他们的顺序为他们命名
- sPoolWorkQueue:任务队列,容量为128
AsyncTask切换线程实现前台和后台线程分离的原理在于使用了Handler和Looper的搭配,我们来看看Looper和Handler的相关变量:
- mHandler:是一个private修饰的Handler常量,而AsyncTask内部的私有方法getHandler就是返回的该成员
- sHandler:是一个private修饰的静态InternalHandler常量,其所绑定的Looper为主线程的Looper,而AsyncTask内部的私有方法getMainHandler会将该Handler初始化,并且返回的该成员
InternalHandler的实现
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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
---------- 重点 1 ----------
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
------------ 重点 2 -------------
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
可见,该Handler的handleMessage方法已经实现了对两种Message的处理;注意,在重点1和重点2处的result.mTask实际就是指正在使用的AsyncTask对象,这里也正好展示了AsyncTask的两个方法finish和onProgressUpdate的调用时机。
二、构造函数
AsyncTask有三个构造函数,但终究还是回调的AsyncTask(Looper callbackLooper)这个构造函数:
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
AsyncTask(Looper):
public AsyncTask(@Nullable Looper callbackLooper) {
--------------- 重点 1 ---------------
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
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
---------------- 重点 2 -------------
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
---------------- 重点 3 ------------
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);
}
}
};
}
首先看注释中的重点 1:
- 执行初始化mHandler的功能,调用无参构造器或者传递的参数为null的话,那么mHandler就会被赋值为getMainHandler的返回值,上文中说这个方法的返回值是sHandler,而sHandler是一个绑定到主线程的Looper上的InternalHandler,也就是说mHandler处理Message发生在主线程。因此在大多情况下我们在主线程下创建AsyncTask时,只需要默认构造器就好。
再看mWorker的初始化:
- 重点2展示了我们在使用AsyncTask的时候需要重写的方法,doInBackground。
- 重点3的功能是将Result交给mHandler处理,所以这个方法才是后台得到的结果可以传到其他的线程去使用的关键:
postResult:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可见,该方法实现了在try块中调用doInBackground执行后台任务,待其执行完毕,得到result之后,在finally块中通过postResult方法将后台线程获取到的结果交给前台线程使用,真实很巧妙优雅的设计。
三、工作流程
1. 入口方法execute(Progress...)方法
该方法的实现只是一个简单的回调:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
executeOnExecutor方法
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;
----------- 重点 1 -----------
onPreExecute();
mWorker.mParams = params;
-------------- 重点 2 --------------
exec.execute(mFuture);
return this;
}
注意,调用该方法的时候exec参数的值为sDefaultExecutor,而上文中说道,sDefaultExecutor的值为SerialExecutor对象,所以说AsyncTask处理任务是按顺序处理的。
- 重点1处又出现了一个我们在使用时可以选择重写的一个方法的调用,而该方法调用发生在exec.execute之前,后者里面会调用mWorker中的call方法触发doInBackground方法;我们可以在onPreExecute方法中做一些准备工作
2. 其他方法
finish方法
当我们使用主线程Looper作为Looper的时候,该方法发生在handler处理POST_RESULT消息的时候:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
他会根据当前AsyncTask是否取消调用不同的方法,当没有取消时,会调用onPostResult方法,因此我们需要重写onPostResult方法来更新我们的UI。
publishProgress方法
该方法可以将progress消息通知到Handler中:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
我们上文中展示过,Handler在处理progress时间时会调用onProgressUpdate方法,所以我们可以重写onProgressUpdate方法来展示进度条等
网友评论