Android中的AsyncTask原理:
在Android开发中,当通过线程去执行耗时的任务,并且在操作完以后可能还会更新UI时,通常还会用Handler类来更新UI线程。总体来说,实现简单,但是如果有多个任务同时执行时则会显得代码臃肿。Android提供了AsyncTask,它使得异步任务实现起来更加简单,代码更简介。
AsyncTask的定义:
public abstract class AsyncTask<Params,Progress,Result>{
……
}
由定义可以看出,AsyncTask是一个抽象的泛型类,3个泛型参数。其中参数Params为参数类型。参数Progress为后台任务执行进度的类型。参数Result为返回结果的类型。如果不需要某个参数,可以将其设置为Void类型。
其中,AsyncTask中有4个核心方法:
1.onPreExecute():在主线程中执行。一般在任务执行前做准备工作。例如对UI做一些标记。
2.doInBackground(Params...params):在线程池中执行。在onPreExecute方法执行后运行,用来执行较为耗时的操作。在执行过程中可以调用publishProgress(Progress...values)来更新进度信息。
3.onProgressUpdate(Progress...values):在主线程中执行。当调用publishProgress(Progress...values)时,此方法会将进度更新在UI组件上。
4.onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,它会被执行。doInBackground方法执行得到的结果就是返回的result的值。此方法一般做任务执行后的收尾工作。比如更新UI和数据。
AsyncTask源码分析:
AsyncTask在3.0版本之前后之后有着较大的改动:
- Android 3.0版本之前的AsyncTask:(部分源码)
public abstract class AsyncTask<Params,Progress,Result>{
private static final String LOG_TAG="AsyncTask";
private static final int CORE_POOL_SIZE=5;
private static final int MAXIMUM_POOL_SIZE=128;
private static final int KEEP_ALIVE=1;
private static final BlockingQueue<Runnable> sWorkQueue=new LinkedBlockingQueue<Runnable>(10) ;
private static final ThreadFactory sThreadFactory = new ThreadFactory()}
private final AtomicInteger mCount=new AtomicInteger(1);
private Thread newThread(Runnable r){
return new Thread(r,"AsyncTask #"+mCount.getAndIncrement());
}
};
private static final ThreadPoolExecutor sExecutor=new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,sWorkQueue,sThreadFactory);
…………
}
上述源码中,又看到了ThreadPoolExecutor,它的核心线程数是5个,线程池允许创建的最大线程数为128,非核心线程空闲等待新任务的最长时间为1s。采用的阻塞队列是LinkedBlockingQueue,容量是10.对于3.0之前的AsyncTask的一个缺点就是线程池最大的线程数为128,加上阻塞队列的10个任务,AsyncTask最多能同时容纳138个任务,当提交到第139个任务的时候就会执行饱和策略,默认抛出RejectedExecutionException异常。
- Android 7.0版本的AsyncTask:
对于Android 3.0以后的AsyncTask 。首先来看AsyncTask的构造方法。
AsyncTask的构造方法如下:
public AsyncTask(){
mWorker=new WorkerRunnable<Params,Result>(){
public Result call() throws Exception{
mTaskInvoked.set(true);
Progress.setThreadPriority(Progcess.THREAD_PRIORITY_BACKGROUND);
Result result=doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(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);
}
}
};
}
由上面的源码可以看出,WorkRunnable实现了Callable接口,并是实现了他的call方法,在call方法中调用了doInBackground(mParams)来处理任务并得到结果,并最终调用postResult将结果投递出去。FutureTask是一个可管理的异步任务,它实现了Runnable和Future这2个接口。因此,它可以包装Runnable和Callable,并提供给Executor执行。也可以调用线程直接执行(FutureTask.run())。在这里WorkerRunnable作为参数传递给了FutureTask。这2个 变量会暂时保存在内存中,稍后会用到它们。当要执行AsyncTask时,需要调用它的execute()方法:
public final AsyncTask<Params,Progress,Result> execute(Params..params){
return executeOnExecutor(sDefaultExecutor,params);
}
execute方法又调用了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;
onPreExecute();
mWorker.mParams=params;
exec.execute(mFuture);
return this;
}
上述源码中,首先调用了onPreExecute()方法,mWorker.mParams=params;将AsyncTask的参数传给WorkRunnable.从前面知道WorkRunnable作为参数传递给了FutureTask。因此,参数被封装到FutureTask中。接下来会调用exec.的execute方法,并将mFuture也就是前面提到的FutureTask传进去。这里的exec是传进来的参数sDefaultExecutor,它是一个串行的线程池SerialExecutor:
private static class SerialExecutor implements Executor{
final ArrayDeque<Runnable> mTasks=new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r){
public void run(){
try{
r.run();
}finally{
scheduleNext();
}
}
};
if(mActive==null){
scheduleNext();
}
}
protected synchronized void scheduleNext(){
if((mActive=mTask.poll())!=null){
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
上面的mTask.offer(new Runnable){…}中,当调用SerialExecutor的execute方法时,会将Future加入到mTasks中。当任务执行完或者当前没活动的任务时都会执行scheduleNext方法,它会从mTasks取出FutureTask任务并交由THREAD_POOL_EXECUTOR处理。从这里可以看出SerialExecutor是串行执行的。在r.run()处可以看到执行了FutureTask的run方法,它最终会调用WorkerRunnable的call方法。前面提到过call方法最终会调用postResult方法将结果投递出去,postResult方法的代码:
private Result postResult(Result result){
@SuppressWarnings("unchecked")
Message message=getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this,result));
message.sendToTarget();
return result;
}
在postResult方法中会创建Message,将结果赋值给这个Message,通过getHandler方法得到Handler,并通过这个Handler发送消息。getHandler方法:
private static Handler getHandler(){
synchronized(AsyncTask.class){
if(sHandler==null){
sHandler=new InternalHandler();
}
return sHandler;
}
}
在getHandler方法中创建了InternalHandler,InternalHandler的定义如下:
private static class InternalHandler extends Handler{
public InternalHandler(){
super(Looper.getMainLooper());
}
@SuppressWarings({"unchecked","RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg){
AsyncTaskResult<?> result=(AsyncTaskResult<?>) msg.obj;
swith(msg.what){
case MESSAGE_POST_RESULT:
//there is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
在收到MESSAGE_POST_RESULT消息后会调用AsyncTask的finish方法:
private void finish(Result result){
if(isCancelled){
onCancelled(result);
}else{
onPostExecute(result);
}
mStatus=Status.FINISHED;
}
如果AsyncTask任务被取消了,则执行onCancelled方法,否则调用onPostExecute方法。正是通过onPostExecute方法,我们才能够得到异步任务执行后的结果。接着回头看SerialExecutor,线程池SerialExecutor主要处理排队,将任务串行处理。在SerialExecutor中调用scheduleNext方法时,将任务交给THREAD_POOL_EXECUTOR.THREAD_POOL_EXECUTOR同样是一个线程池,用来处理任务:
private static final int CPU_COUNT=Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE=Math.max(2,Math.min(CPU_COUNT-1,4));
private static final int MAXIMUM_POOL_SIZE=CPU_COUNT*2+1;
private static final int KEEP_ALIVE_SECONDS=30;
private static final BlockingQueue<Runnable> sPoolWorkQueue=new LinkedBlockingQueue<Runnable>(128);
public static final Executor THREAD_POOL_EXECUTOR;
static{
ThreadPoolExecutor threadPoolExecutor=new threadPoolExecutor(
CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE_SECONDS,TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR=threadPoolExecutor;
}
THREAD_POOL_EXECUTOR指的就是threadPoolExecutor,其核心线程和线程池允许创建的最大线程数是由CPU的核数计算出来的。它采用的阻塞队列仍然是LinkedBlockingQueue,容量为128.
- 在AsyncTask中哟个到了线程池,在线程池中运行线程,并且又用到了阻塞队列。Android 3.0以上版本用SerialExecutor作为默认的线程,它将任务串行的处理,保证一个时间段只有一个任务执行。而Android 3.0之前的版本是并行处理的。Android 3.0之前的版本的缺点在3.0以后的版本中也不会出现,因为线程是一个接着一个执行的,不会出现超过任务数而执行饱和策略的情况。如果想要在3.0及其以上版本使用并行的线程处理,可以使用:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR," ");
其中,asyncTask是我们自定义的AsyncTask,当然也可以传入4种线程池,比如传入CachedThreadPool:
asyncTask.executeOnExecutor(Executors.newCachedThreadPool()," ");
还可以传入自定义的线程池:
Executor exec=new ThreadPoolExecutor(0,Integer.MAX_VALUE,0L,TimeUnit.MILLSENDS,new LinkedBlockingQueue<Runnable>());
asyncTask.executeOnExecutor(exec," ");