简介
AsyncTask 是一个 Thread 和 Handler 的助手类。
通过该类,可以轻松的创建 需要把结果发布到UI线程的短期后台操作。
(长时间后台操作推选使用 java.util.concurrent 的API)
在API 11前,线程池是一个普通的ThreadPoolExecutor,支持并发:
new ThreadPoolExecutor(5, 128, 10, TimeUnit.SECONDS,
LinkedBlockingQueue<Runnable>(10), ThreadFactory);
在API 11后,线程池是一个维护了Runnable队列的SerialExecutor,支持串行:
new SerialExecutor();
注意到的是,SerialExecutor内部实际是通过一个支持并发的线程池工作的:
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
[2,4], CPU*2+1, 30, TimeUnit.SECONDS,
LinkedBlockingQueue<Runnable>(128), ThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
而AsyncTask支持通过executeOnExecutor执行在指定的线程池,所以如果需要执行并发任务的时候,可以直接使用
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
而无需重新自定义线程池。
基本行为
AsyncTask的行为被定义为2块:
-
泛型参数 <Params, Progress, Result>
用于定义AsyncTask执行时使用的3种参数的类型:public abstract class AsyncTask<Params, Progress, Result> {...} Params :执行时传入的参数的类型; Progress :进度更新时传出的参数的类型; Result :执行完成时返回的参数的类型;
-
执行步骤
AsyncTask执行时主要的4个步骤方法:@MainThread protected void onPreExecute() {} :在后台任务开始前的初始化方法,执行在UI线程,可以用于设置任务 @WorkerThread protected abstract Result doInBackground(Params... params){...} :onPreExecute之后马上执行,后台任务的执行方法,也是AsyncTask的核心方法,在后台线程中执行 执行过程中,可以使用publishProgress通知后台任务的进度更新 执行结束时,返回的结果会作为onPostExecute的参数 @MainThread protected void onProgressUpdate(Progress... values) {...} :调用publishProgress后执行,执行在UI线程,用于执行后台进度变更时需要变化的逻辑 @MainThread protected void onPostExecute(Result result) {...} :后台任务完成时调用,执行在UI线程,用于接收执行结果处理后台任务执行完成的逻辑
工作原理
AsyncTask主要的工作可以概括成:
- 后台耗时任务,AsyncTask的工作主体
- 在UI线程的任务进度通知以及任务完成通知
在AsyncTask的说明中提及,该类只是一个Thread和Handler的辅助类,而不是一个标准的线程操作框架:
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
and does not constitute a generic threading framework.
其中涉及到的内容:
- Thread :后台工作的所在线程,由预置或自定义线程池维护
- Handler:从后台线程切换到UI线程的核心,完成所有后台任务中对通知UI线程的通知操作
线程切换
AsyncTask中对Thread和Handler的处理切换,主要由以下的对象完成:
private final Handler mHandler;
:AsyncTask对象的成员,指向AsyncTask静态成员sHandler
private static InternalHandler sHandler
= new InternalHandler(Looper.getMainLooper())
:传入Looper.getMainLooper()说明运行在主线程
负责AsyncTask从工作线程切换到主线程,执行如onProgressUpdate等方法
private static class InternalHandler extends Handler {
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
:AsyncTaskResult<?> result在下面分析
这里主要关注sHandler的工作内容,sHandler处理的工作主要有:
1.MESSAGE_POST_RESULT : 对应方法为onPostExecute()
2.MESSAGE_POST_PROGRESS : 对应方法为onProgressUpdate()
在该处可以推断出:推送到sHandler的消息基本来自子线程,通过sHandler实现UI线程的切换
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
:推送到sHandler的消息的数据封装,主要封装了当前的AsyncTask和操作参数
1.mTask:需要执行UI线程任务的AsyncTask对象
2.mData:AsyncTask执行UI线程任务的参数,在推送<Progress>参数时,可以是多参数的
以上的部分完成UI线程的工作任务,且反映了:
AsyncTask 的 onPostExecute() 和 onProgressUpdate() 运行在UI线程依赖的是Handler机制。
执行任务
- 从execute开始
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
:调用execute方法时,实际上调用了executeOnExecutor方法
传入的线程池,则是上面简介中提到的SerialExecutor,一个串行执行任务的线程池
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) ... ...
:检查AsyncTask实例的运行状态
AsyncTask每一个实例,只允许执行一次(execute)
除了PENDING,其余状态都会抛出IllegalStateException
mStatus = Status.RUNNING;
onPreExecute();
:修改为运行中状态,在UI线程中执行AsyncTask的预处理方法
mWorker.mParams = params;
exec.execute(mFuture);
:这里涉及到了一个mWorker对象,属于后台线程运行部分,下一部分说明
大体上,mWorker是一个Callable,负责AsyncTask的后台任务调用过程
return this;
}
:executeOnExecutor大体上负责了2个内容:
1.判断当前执行状态
2.使用传入的线程池,执行AsyncTask的后台任务
- 执行后台任务
使用传入的线程池执行AsyncTask的后台任务,具体的执行流程,封装在mWorker
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result>
implements Callable<Result> {
Params[] mParams;
}
:mWorker是 WorkerRunnable类的实例
本质上是一个保存了Params参数的Callable对象
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
:设置调用状态为已被调用
在该状态设置前,doInBackground被标识为未调用
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
:设置线程优先级为后台线程,执行doInBackground
} catch (Throwable tr) {
mCancelled.set(true);
:当发生异常时,设置AsyncTask取消状态为已取消
throw tr;
} finally {
postResult(result);
:发送执行结果,属于执行完成的部分,后面介绍
}
return result;
}
};
:mWorker负责处理了doInBackground的逻辑
以及doInBackground完成后调用postResult发送执行结果
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(..., e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
:mFuture是包裹mWorker的FutureTask对象
这里的逻辑基本上只有一种情况会发生,即 doInBackground抛出异常或错误,
导致 get() 方法调用时抛出 ExecutionException,然后 done() 方法抛出 RuntimeException
- 发送执行结果
private Handler getHandler() {
return mHandler;
}
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
:把执行结果发送到mHandler,意味着在主线程执行
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
:mHandler处理执行结果的逻辑,调用了mTask的finish方法
public final boolean isCancelled() {
return mCancelled.get();
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
:根据执行状态选择需要调用的方法
1.onCancelled() 即任务被取消
2.onPostExecute() 即任务完成
mCancelled为true的情况有2种
1.调用了AsyncTask的cancel()方法取消任务
2.doInBackground()的过程中抛出异常,导致任务被取消
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
@MainThread
protected void onCancelled() {
}
@MainThread
protected void onPostExecute(Result result) {
}
:执行结果的方法都可以根据需求重写
以上就是AsyncTask的工作过程。
网友评论