Android中的AsyncTask原理

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版本之前后之后有着较大的改动:

  1. 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异常。

  1. 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.


  1. 在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," ");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒不了的星期八

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值