在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
因此,一个最简单的自定义AsyncTask就可以写成如下方式:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
……
}
这里我们把AsyncTask的第一个泛型参数指定为Void,表示在执行AsyncTask的时候不需要传入参数给后台任务。第二个泛型参数指定为Integer,表示使用整型数据来作为进度显示单位。第三个泛型参数指定为Boolean,则表示使用布尔型数据来反馈执行结果。 当然,目前我们自定义的DownloadTask还是一个空任务,并不能进行任何实际的操作,我们还需要去重写AsyncTask中的几个方法才能完成对任务的定制。
经常需要去重写的方法有以下四个:
onPreExecute()
这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。doInBackground(Params...)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return
语句来将任务的执行结果进行返回,如果AsyncTask
的第三个泛型参数指定的是Void
,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)
方法来完成。onProgressUpdate(Progress...)
当在后台任务中调用了publishProgress(Progress...)
方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。onPostExecute(Result)
当后台任务执行完毕并通过return
语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。在android1.6以前,它是串行执行,android1.6开始采用线程池处理并行任务,从android3.0开始,采用串行执行任务,仍然可以调用executeOnExecute方法并行执行任务。Android 3.0之前,AsyncTask核心线程数为5个,最大核心线程数为128个,加上阻塞队列任务10个共容纳138个任务,当提交的任务超过138个时就会执行饱和策略,抛出异常。
AsyncTask
内部有两个线程池(SerialExecutor
与THREAD_POOL_EXECUTOR
)和一个IntentHandler
, SerialExecutor
用于任务排队,THREAD_POOL_EXECUTOR
用于真正执行任务,IntentHandler
用于将执行环境从线程池中切换到主线程。
创建AsynacTask并初始化必须在主线程中执行
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */
public AsyncTask() {
this((Looper) null);}/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
创建一个异步任务AsyncTask
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
getMainHandler
方法并初始化InternalHandler? 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
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);
}
}
};
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
sHandler是一个静态变量,将执行环境切换到主线程,这就要求sHandler在主线程中创建,静态成员变量会在加载类时进行初始化变相要求AsyncTask在主线程中加载
private static InternalHandler sHandler;
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//发送消息切换到主线程中执行
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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
//执行finish方法
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//执行onProgressUpdate方法
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
//如果当前任务取消了,就调用onCancelled,否则调用onPostExecute方法
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
//doBackground方法调用publishProgress方法从子线程切换到主线程进行UI更新
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
SerialExecutor源码分析
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
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);
}
}
}
SerialExecutor使用ArrayQueue来管理Runnable对象,当一次性启动很多任务时,首先第一次运行executor方法,会调用ArrayQueue将任务添加到队列尾部,并判断mActive是否为空,为空调用scheduleNext方法,这个方法会从队列头部取值,然后赋值给mActive,然后调有THREAD_POOP_EXECUTOR取出并执行runnable对象。之后又有新任务,将会调用offer将runnable传入队列尾部,此时mActivie不为空,就不调用scheduleNext方法。
每当任务执行完毕后才会执行下一个任务,SerialExecutor模仿的是单一线程池操作,同一时刻只会有一个任务执行。