AsyncTask是Android提供了一个异步执行的库,它的主要功能是,在UI线程中创建和调用,在后台执行耗时任务,执行任务时或者执行完成后可以更新界面。
基本使用
//AsyncTask<传入参数类型,进度类型,结果类型>,构造函数必须在UI线程中调用
new AsyncTask<Void,Integer,String>(){
@Override
protected void onPreExecute() {
//处于UI线程,在开始执行耗时任务之前调用
}
@Override
protected String doInBackground(Void... params) {
//处于后台进程,执行耗时任务,返回任务结果
//do something
publishProgress(30); // 将会调用 onProgressUpdate
//do something ...
publishProgress(100); // 将会调用 onProgressUpdate
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
//处于UI线程,更新任务进度信息
}
@Override
protected void onPostExecute(String s) {
//处于UI线程,在doInBackground返回后被调用,用于显示结果信息
}
@Override
protected void onCancelled(String s) {
//处于UI线程,在调用AsyncTask.cancel()并且doInBackground执行完成之后被调用
//如果这个函数被调用,将不会调用onPostExecute
}
}.execute();
实现原理
一切真相都在源码中
//带返回参数的执行体接口,和Runnable类似,只是Runnable是无接口的
public interface Callable<V> {
V call() throws Exception;
}
//定义WorkerRunnable,增加了一个参数数组mParams
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
//构造函数(精简了部分代码,只保留关键代码)
public AsyncTask() {
//这里定义了一个WorkerRunnable,它是一个执行体,将会被投到某个线程中执行
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//执行耗时任务
Result result = doInBackground(mParams);
//返回执行结果
return postResult(result);
}
};
//使用FutureTask对WorkerRunnable进行再次封装,目的是即使WorkerRunnable没有被执行(没有调用call函数),也可以返回结果(在取消执行的情况下,done会被调用)。
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
postResultIfNotInvoked(get());
}
};
}
//执行任务,必须在UI线程中调用
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);//将构造函数创建的FutureTask扔到线程中执行
return this;
}
//接收执行结果,看代码是将结果发送到一个Handler中去了
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper()); //使用了UI线程的Looper
}
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);//执行完成
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);//显示进度信息
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);//调用取消回调函数
} else {
onPostExecute(result);//调用结果显示函数
}
}
分析完源码后,可以总结原理了:先创建一个Callable,将Callable丢到线程中执行,然后将结果发送给Handle处理。
串行OR并行
相信很多Android开发都会发现,默认情况下,多个AsyncTask居然是串行执行的,这个和Thread是完全不一样的,简直是个坑啊!
上面是使用sDefaultExecutor来执行耗时任务的,看下定义:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
显然这是一个串行执行的线程池,所以在app中使用多个asyncTask时,会变成串行执行。。。
简直不能忍,我要换回Thread去!
其实还是有办法的,AsyncTask当然可以并发了,看代码:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
//这里定义了一个线程池,最大线程数是CPU_COUNT * 2 + 1
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//使用方法
new AsyncTask....(){
//...
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
什么? 你跟我说并发数不够? 了解原理的我们分分钟自己创建一个大容量线程池给AsyncTask用。
===============================睡觉线===========================