7.5 异步任务类AsyncTask
Android在框架层提供了异步任务(Asynchronous Task)类AsyncTask[1],用于执行后台任务,并将执行结果更新到UI线程。
AsyncTask是一个抽象类,其定义如下:
/*Params、Progress、Result是泛型,需要子类指定具体的数据类型。Params
指定异步任务的输入参数,Progress指定执行过程,Result指定执行结果/
public abstract class AsyncTask<Params, Progress, Result>{
……
private static volatile Executor sDefaultExecutor=SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR=new SerialExecutor();
private final WorkerRunnable<Params, Result>mWorker;
private final FutureTask<Result>mFuture;
private volatile Status mStatus=Status.PENDING;
……
//抽象方法,放置任务的执行代码,需要子类实现
protected abstract Result doInBackground(Params……params);
//任务的默认执行入口,指定sDefaultExecutor为默认执行器
public final AsyncTask<Params, Progress, Result>execute(Params……params){
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result>executeOnExecutor(
Executor exec, Params……params){
if(mStatus!=Status.PENDING){//创建任务时,默认为PENDING
switch(mStatus){
case RUNNING://已经执行的任务不能重复执行
throw new IllegalStateException("……");
case FINISHED://已经执行完的任务不能被执行
throw new IllegalStateException("……");
}
}
mStatus=Status.RUNNING;//任务进入运行状态
onPreExecute();
//该方法可由子类覆盖
mWorker.mParams=params;//将传入的参数存入mWorker中
exec.execute(mFuture);//mFuture是Runnable的子类
return this;
}
……
}
由以上代码可知,AsyncTask是一个抽象类,提供了抽象的doInBackground方法用于执行后台任务。使用AsyncTask时,需要定义其子类,并在子类中实现doInBackground方法,以提供具体的后台处理任务。doInBackground实际是在另外一个线程中执行的,后续将会分析。
7.5.1 AsyncTask的实现
AsyncTask提供了Status类型的mStatus成员变量,用于表示异步任务的运行状态。mStatus可以是PENDING、RUNNING、FINISHED三种状态,但只有处于PENDING状态的异步任务才能被执行,当异步任务处于RUNNING或者FINISHED状态时,说明该异步任务已经在执行或者执行完毕,此时如果重新执行该异步任务会抛出IllegalStateException。
AsyncTask提供了SerialExecutor类型的默认执行器用于执行异步任务。
AsyncTask定义了WorkerRunnable<Params, Result>类型的mWorker成员变量,用于存储异步任务的参数。WorkerRunnable是一个AsyncTask抽象内部类,由子类实现。
AsyncTask定义了FutureTask<Result>类型的mFuture成员变量,用于存储异步任务。
AddCallTask是AsyncTask的子类之一,这里以该子类为例,分析如何实现一个异步任务,它位于packages/apps/Phone/src/com/android/phone/CallLogAsync.java中,代码如下:
//AddCallArgs代替Params, Void代替Progress, Uri[]代替Result
private class AddCallTask extends AsyncTask<AddCallArgs, Void, Uri[]>{
@Override
protected Uri[]doInBackground(AddCallArgs……callList){
……//实现了父类AsyncTask的doInBackground方法,该方法将在其他线程中调用
}
@Override
protected void onPostExecute(Uri[]result){
……//覆盖了父类AsyncTask的onPostExecute方法,运行于UI线程
}
}
public AsyncTask addCall(AddCallArgs args){
assertUiThread();//AsyncTask必须在UI线程中创建
return new AddCallTask().execute(args);//创建任务,并执行
}
由以上代码可知,使用异步任务的步骤如下:
1)定义AsyncTask的子类,并在子类中实现doInBackground方法。
2)调用子类的execute方法执行该异步任务。
子类AddCallTask的execute方法继承自父类AsyncTask的execute(Params……params)方法。调用execute方法进而会执行executeOnExecutor方法。executeOnExecutor方法会接收两个参数sDefaultExecutor和params,本例中sDefaultExecutor是SerialExecutor类型的默认执行器,params则是传入的AddCallArgs类型的args参数。
在executeOnExecutor方法内部主要做如下工作:
1)判断当前异步任务的状态,如果是RUNNING或者FINISHED状态,则抛出IllegalStateException异常,这样保证当前异步任务只能执行一次。
2)调用onPreExecute方法做一些预处理工作,该方法可以由子类覆盖。
3)将传入的args参数存入WorkerRunnable类型的mWorker成员变量的mParams中。
4)调用sDefaultExecutor的execute方法。传入该方法的参数是FutureTask类型的mFuture成员变量。
前两部分工作比较简单,后两部分工作涉及mWorker和mFuture这两个成员变量,它们的类型分别是WorkerRunnable和FutureTask,这两个成员变量共同描述了一个异步任务,需要详细分析。
1.WorkerRunnable类
WorkerRunnable是AsyncTask的内部类,其定义如下:
private static abstract class WorkerRunnable<Params, Result>implements Callable<Result>{
Params[]mParams;
}
可见WorkerRunnable是一个抽象内部类,其实现了Callable接口,内部定义了一个mParams成员变量,其类图如图7-3所示。
图 7-3 WorkerRunnable类
Callable接口提供了call方法,WorkerRunnable实现了Callable接口,但并没有实现接口的call方法,因此WorkerRunnable定义为抽象类。
WorkerRunnable的成员变量mParams用于存储异步任务的Params数据,Params是一个泛型参数,由WorkerRunnable的子类提供具体的参数类型。
mWorker在AsyncTask的构造函数中初始化,代码如下:
private final AtomicBoolean mTaskInvoked=new AtomicBoolean();
……
public AsyncTask(){
mWorker=new WorkerRunnable<Params, Result>(){
public Result call()throws Exception{
mTaskInvoked.set(true);
Process.setThreadPriority(//调整线程优先级为后台线程
Process.THREAD_PRIORITY_BACKGROUND);
//将在call方法中调用doInBackground
return postResult(doInBackground(mParams));
}
};
……
}
在AsyncTask的构造方法中,通过匿名类(在类图中以XXWorkerRunnable表示)实现了抽象类WorkerRunnable,并提供了call方法。call方法将线程优先级调整为后台线程,然后会执行doInBackground方法,该方法的返回结果会传入postResult方法中用于更新UI线程,这部分内容后续会分析。
接下来分析FutureTask类。
2.FutureTask类
FutureTask类定义在libcore/luni/src/main/java/java/util/concurrent/FutureTask.java中,是Java多线程编程模型的一部分,其类图如图7-4所示。
图 7-4 FutureTask类
FutureTask实现了Runnable Future接口,Runnable Future接口则继承自Runnable接口和Future接口。其中Runnable接口是Java标准线程模型的一部分,可以通过Thread类将Runnable封装成一个线程;Future接口提供了异步任务的控制方法,如取消、获取和判断异步任务的执行情况。因此FutureTask是一个同时具备线程属性和异步任务控制属性的类。
FutureTask同样在AsyncTask的构造方法中初始化,代码如下:
public abstract class AsyncTask<Params, Progress, Result>{
……
private final FutureTask<Result>mFuture;
……
public AsyncTask(){
mWorker=……//省略mWorker赋值过程
//将mWorker传入FutureTask的构造函数中
mFuture=new FutureTask<Result>(mWorker){
@Override
protected void done(){//覆盖了父类的done方法
try{
postResultIfNotInvoked(get());
}catch(InterruptedException e){
android.util.Log.w(LOG_TAG, e);
}catch(ExecutionException e){
throw new RuntimeException(……);
}catch(CancellationException e){//异步任务取消时的处理流程
postResultIfNotInvoked(null);
}
}
};
}
mFuture的初始化过程涉及一个重要成员变量sync的赋值操作。传入FutureTask构造函数的参数是mWorker,该参数最终封装到mFuture的成员变量sync中,代码如下:
public class FutureTask<V>implements RunnableFuture<V>{
private final Sync sync;
//mWorker是WorkerRunnable类型的对象,其父类为Callable
public FutureTask(Callable<V>callable){
if(callable==null)
throw new NullPointerException();
sync=new Sync(callable);//将mWorker封装到sync的callable成员变量中
}
由以上代码可知,mFuture在初始化过程中将mWorker封装到mFuture成员变量sync的callable中,因此mWorker和mFuture共同表示一个异步任务。
接下来分析异步任务的执行。
[1]AsyncTask的详细概念请参考http://developer.android.com/reference/android/os/AsyncTask.html。