AsyncTask源码分析
当使用到线程处理网络操作或者其他需要用到线程的时候,经常会用到AsyncTask来进行异步操作.以下是常用的几个方法.
/*
* 第一个参数类型,是doInBackground所接收的参数类型
* 第二个参数类型是onProgressUpdate所接收的参数类型
* 第三个参数类型是doInBackground返回的参数类型,也是onPostExecute接收的参数类 型
*/
public static class MyTask extends AsyncTask<String, Integer,String>{
/*
* 在执行doInBackgroud之前,运行在UI线程(即主线程)上
* 主要执行一些预备的操作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/*
* 运行在一个后台线程上,这里执行所需的网络操作
* 可以调用publishProgress来在UI线程上更新进度
*/
@Override
protected String doInBackground(String... params) {
return null;
}
/*
* 在执行publishProgress函数后
* 运行在UI线程上,拿到publishProgress传入的values值
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/*
* 运行在UI线程上,传入的参数是doInBackground执行之后的返回值
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
//调用execute(),并传入参数
MyTask task = new MyTask();
task.execute("http://www.baidu.com");
对于这几个方法都已经使用非常熟悉了
以下图片很形象地描述了AsyncTask的线程是如何切换的
更多关于AsyncTask需要注意的问题:https://ptodue.gitbooks.io/book2/content/2.2.html
现在,正式从源码里面来了解到底是如何切换的
以上是AsyncTask所有的方法.
我们调用的时候代码如下:
MyTask task = new MyTask();
task.execute("http://www.baidu.com");
MyTask 继承 AsyncTask,那么执行new MyTask()的时候,会执行到AsyncTask的构造函数
进入代码里面:
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
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
);
//noinspection unchecked
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()
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
关于Callable和FutureTask
Callable位于java.util.concurrent包下
public interface Callable<V> { V call() throws Exception;}
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型
Callable一般是和ExecutorService配合来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本,其中一个为
<T> Future<T> submit(Callable<T> task);
Future可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
public interface Future<V> { ... V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。
public class FutureTask<V> implements RunnableFuture<V> public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); } //提供的构造器 public FutureTask(Callable<V> callable) {}
FutureTask既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
初始化MyTask完之后,对成员mWorker和mFuture进行初始化,接下来就是调用execute函数
task.execute("http://www.baidu.com");
根据这一句,进入execute函数
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"+ " the task is
already running.");
case FINISHED:
throw new IllegalStateException("Cannot executetask:" + " 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;
}
可以看到,现在默认的Executor是一个new SerialExecutor()的实例.
进入到executeOnExecutor之后,看到最关键的三句代码
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
这就解释了在doInBackground之前,执行onPreExecute();
之前在doInBackground(mParams)中,mParams的值就是这个时候传进来的值params
最后执行
exec.execute(mFuture)
执行mFuture.
继续回到mFuture这边,mFuture = new FutureTask<Result>(mWorker)
,通过传入mWorker调用里面的call()函数,先看看mWorker实现的call()接口
mTaskInvoked.set(true);
Process.setThreadPriority(
Process.THREAD_PRIORITY_BACKGROUND
);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
mTaskInvoked是一个原子性的布尔值, 在这个Boolean值的变化的时候不允许在之间插入,保持操作的原子性.
Process设置线程的优先级.
然后看到了最熟悉的doInBackground(mParams),其中mParams前面已经被赋值了.
Binder.flushPendingCommands();
这里把任何在当前线程即将执行的Binder的命令Flush到内核驱动中.在长时间阻塞的操作调用,来确保即将用到的对象引用被释放,这样可以防止进程持有对象的时间长于需要的时间.
最后执行到postResult()
new FutureTask中最后会执行postResultIfNotInvoked(get())
这个函数,get()拿到的是mWorker的结果.
然后postResultIfNotInvoked函数里面执行的最后也是 postResult(),通过mTaskInvoked来保证最后都会执行到postResult()
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
进入到postResult()函数
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(
MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result)
);
message.sendToTarget();
return result;
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
该函数返回当前的result,并且通过Handle消息传递,传递进去一个 AsyncTaskResult.
可以看到 AsyncTaskResult类持有一个当前的AsyncTask 和 处理的结果Result.然后通过调用obtainMessage传递消息过去
平时调用会用到publishProgress
,实际上也通过Handle来传递信息
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this,values)).sendToTarget();
}
}
看看整个Handle如何处理
private static InternalHandler sHandler;
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (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;
}
}
}
这个Hansdler执行Looper.getMainLooper(),拿到主线程的Looper(),根据传递的消息,会执行到当前该AsyncTask的finsh函数.
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
可以看到,如果没有执行onCancelled函数,就会执行到onPostExecute.
这也就是解释了,doInBackground在后台执行完产生结果,通过Handle传递消息,Looper.getMainLooper()切换到主线程,执行onPostExecute,传入的参数就是doInBackground返回的结果.,如果有publishProgress,实际上也是通过Handle传递消息,切换到主线程,传递进来values,作为onProgressUpdate的参数.
以上是new一个示例的过程,然后mFuture被执行了,就会一直到最后的Handle.整个逻辑执行就是这样子.
深入到Executor
到这里,其实还可以深入细节里面分析.先回到执行mFuture的那一句
exec.execute(mFuture);
这里的exe是 SerialExecutor的实例
进入SerialExecutor类的代码
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
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);
}
}
}
在execute这个函数里面,队列mTasks入队一个new Runnable()的匿名类并实现了run()接口.可以看到传进来的mFuture会被向上转型成Runnable,并执行其run函数.
mActive一开始为空,执行到scheduleNext()
.会从mTask队列出队一个值并赋给了mActive,然后会通过线程池来执行这个出队的new Runnable()的匿名类.
假如有很多个任务传进来,那么mTask就继续入队,此时mActive不为空了,但是从以下代码可以看出,每次上一个任务执行完,最后都会执行到scheduleNext(),然后继续出队一个值赋给了mActive,并执行mActive.如此把每一个任务都执行完.
private static final int CPU_COUNT = Runtime.getRuntime(). availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
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());
}
};
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;
}
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
THREAD_POOL_EXECUTOR最后被赋值一个线程池.
所以最后是通过一个线程线程池来执行最后的mFuture