最近想写一篇关于源码解析的文章,发现AsyncTask代码量不多,可里面的东西却是很值得学习的,所以故那这来“开刀”
首先作为Android开发者我们对于AsyncTask想必比大家都知道吗,大白话讲就是在后台执行耗时任务再把最终的结果返回主线程更新UI。如下代码就它的模板代码:
class MyAsyncTack extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
//doInBackground执行前一些初始化的操作都在这里
}
@Override
protected String doInBackground(Void... voids) {
//后台耗时任务执行中。。。
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//后台执行的任务会发回一个或多个阶段性进度结果,这个是可以用来去更新交互页面。
}
@Override
protected void onCancelled() {
super.onCancelled();
//在后台任务被取消时回调
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//耗时任务完成返回结果,刷新ui
}
}
//执行AsycnTask
MyAsyncTack myAsyncTack=new MyAsyncTack();
myAsyncTack.execute();
这就是整的一个AsyncTask模板代码了。
从上面的模板中,整个过程是从myAsyncTack.execute();开始的,那我们就execute()开始吧
AsyncTask关于这部分的源码如下:
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask 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;
}
从上面的代码我们可以看出AsyncTask通过判断Status来防止AsyncTask多次执行,然后调用了onPreExecute();抽象方法,为任务的执行做一些准备和初始化操作。接着有三个对于现在我们来说很陌生的变量(mWorker,exec,mFuture).
对于mWorker,mFuture这两个变量在AsyncTask这个类初始化的时候就已经初始化了,对应的关键源码如下
public AsyncTask() {
this((Looper) null);
}
private static abstract class WorkerRunnable implements Callable {
Params[] mParams;
}
public AsyncTask(Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper);
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask(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);
}
}
};
}
如上所示,mWorker很简单,就是AsycnTask里面的抽象内部类,实现了Callable接口,接下来就是mFuture即FutureTask,对于平时写业务层的我们对这个FutureTask类接触的还是比较少而又是这篇文章的重点,所以重点讲。
FutureTask
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。概念总是难以理解,所以给你们一个关于使用FutureTask的demo,这个demo就是整个AsyncTask的核心。
public class FutureTest1 {
public static void main(String[] args) {
Task task = new Task();// 新建异步任务
FutureTask future = new FutureTask(task) {
// 异步任务执行完成,回调
@Override
protected void done() {
try {
System.out.println("future.done():" + get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
// 创建线程池(使用了预定义的配置)
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(future);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
// 可以取消异步任务
// future.cancel(true);
try {
// 阻塞,等待异步任务执行完毕-获取异步任务的返回值
System.out.println("future.get():"+future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
// 异步任务
static class Task implements Callable {
// 返回异步任务的执行结果
@Override
public Integer call() throws Exception {
int i = 0;
for (;i<10;i++) {
try {
System.out.println(Thread.currentThread().getName()+"_"+ i);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i;
}
}
}
上面demo运行结果如下:
FutureTask可以获取异步任务线程的最终结果,所以future.get()返回10。
回到我们的AsyncTask里,同理如上面demo一样,会先执行mWorker的call()里面的方法,call方法里就执行抽象方法doInBackground(mParams);我们就这回到方法里执行耗时任务,然后拿到结果执行postResult(result)方法,而Future的get()也可以从Callable拿到执行的结果。
- 分析exec.execute(mFuture);
首先exec我们要知道exec是什么?顺着他的源码向上找,代码如下:
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这个sDefaultExecutor是什么呢,再顺着这推,关键源码如下:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext(){
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
ArrayDeque是一个先进先出的队列存储Runnable对象,offer方法加到队尾,poll()从队头取,当运行的第一次的时候mActive就是空的,所以还是从mTask取出一个由THREAD_POOL_EXECUTOR执行,等下一次是mActive不为空就通过finally去执行 scheduleNext();方法,这段代码里有两个讲解点,分别是 r.run();和THREAD_POOL_EXECUTOR
- 首先r.run()调用的是哪个方法呢
通过exec.execute(mFuture);我们知道上面的Runnable就是mFuture,即调用了mFuture.run();而这个源码如下:
private Callable callable;
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public void run() {
if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
我已经把相关的代码都截出来的很详尽了,可以看出callable就是我们上面的mWorker变量,然后就是调mWorker.call()方法执行抽象方法doInBackground(),
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
同时我上面FutureTask的demo也和这个形成了对应连贯,这就是我demo的底层实现,最后通过postResult();里的sHandler发送一个MESSAGE_POST_RESULT的消息
我们追踪先关代码:
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
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);
}
mStatus = Status.FINISHED;
}
这里反而没什么好讲的,通过handler调用finish()方法,假如没有取消就是调用抽象方法onPostExecute(),假如取消了就调用抽象方法onCancelled();而当handler发送MESSAGE_POST_PROGRESS,就是调抽象方法onProgressUpdate(),很简单没什么说的。
- 接着分析THREAD_POOL_EXECUTOR,相关源码如下:
private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(128);
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 ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
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;
}
其实这就是定义了一个线程池。同时运行线程数Math.max(2, Math.min(CPU_COUNT - 1, 4)),线程池总大小CPU_COUNT * 2 + 1;但是由于SerialExecutor的存在,它会强制串行并发,所以实际上只有一个线程在跑,所以也就不存在任务数超过线程池总大小的问题了。当然这是一个默认实现,我特也可以通过public static void setDefaultExecutor(Executor exec)进行更改。
到此整个分析过程就结束了,总结一下AcyncTask汇集了线程池,handler等相关知识,也告诉我们,不管表明多花俏,底层原理才是最重要的,懂得底层原理才能不变应万变,废话有点多了