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.5 异步任务类AsyncTask - 图1

图 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.5 异步任务类AsyncTask - 图2

图 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。