AsyncTask是由Android提供的一个轻量级的异步类,其内部分封装了线程池和Handler。相信绝大多数的Android开发者都接触过它,简单粗暴的就实现了异步网络请求,UI更新。在开始源码分析执行过程前,先看一张图,主要抽取了执行过程中比较关键的几个属性。
下面开始进行源码的分析,先从一段简单的示例代码开始。
public class MainActivity extends AppCompatActivity {
private ProgressDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dialog = new ProgressDialog(this);
dialog.setMax(100);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
new MyAsyncTask().execute();
}
class MyAsyncTask extends AsyncTask<Void,Integer,Boolean> {
private int counter=0;
//当我们调用了execute(),即开始执行异步任务时调用,做一些初始化操作
@Override
protected void onPreExecute() {
dialog.show();
}
//在这里处理所有的耗时任务,会在子线程中执行,返回的结果会传递给onPostExecute()中的参数
@Override
protected Boolean doInBackground(Void... voids) {
while (true){
counter++;
//获取当前任务进度,会执行onProgressUpdate,更新状态
publishProgress(counter);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (counter>=100){
break;
}
}
return true;
}
//处理来自publishProgress的信息
@Override
protected void onProgressUpdate(Integer... values) {
dialog.setProgress(values[0]);
}
//对doInBackground返回的结果进行处理
@Override
protected void onPostExecute(Boolean b) {
if (b){
dialog.dismiss();
}
}
}
}
根据上面的代码,可以知道AsyncTask需要在主线程中实例化,执行execute();每个方法的作用已经注释,接下来说明下AsyncTask<>中的三个参数:
第一个参数:执行execute()需要输入的参数,会在doInBackground()中处理后台任务时使用。
第二个参数:如果需要清楚后台任务的进度,可以通过这个参数转换成进度单位,在onProgressUpdate()中显示。
第三个参数:这个参数是doInBackground()在任务完毕时返回的参数,会传递给onPostExecute().
蓄能完毕,面对疾风吧~~
1、我们从上面的示例代码获取MyAsyncTask示例开始,这时看看AsyncTask源码构造函数中做了什么事:
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return 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);
}
}
};
}
啥也没看出来,只知道初始化了三个变量值^_^。细分析下:还是有的么,在初始mFuture 时mWorker作为参数传入,从上面图中可以知道mWorker是一个Callable(WorkerRunnalbe)对象,重写了call()方法,在call方法里面可以看到一个关键性的字眼doInBackground,这就说明(顺利进行的情况下),任务的执行最终会调用mWorker的call方法。打完,收工!
如果你以为到这就结束了,送哥们两个字“呵呵”。折腾的还在后面呢。
2、来,一起看看为什么最终会调用mWorker的call方法。上面我们已经获取了实例,那下面就是开始执行了, new MyAsyncTask().execute();研究下execute()做了什么事情。
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 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;
}
进去execute里面,发现又调用了executeOnExecutor;可以看到,在executeOnExecutor里面,把AsyncTask的状态为RUNNING,然后调用onPreExecute(),这个地方依然是执行在主线程当中的,因此,可以在onPreExecute中做一些初始化操作。
mWorker.mParams = params; 把传入的参数保存在mWorker中;
跟着就到了exec.execute(mFuture); exec即是传入的sDefaultExecutor,看下面的代码就知道这个是什么了。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
根据上面的代码,exec.execute(mFuture)其实就是执行了SerialExecutor的execute方法。脑海中时刻幻想着最上面的图片(^▽^)
3、接下来我们看下execute里面做了什么事。
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);
}
}
}
这时,我们可以看出,执行SerialExecutor的execute时会把mFuture加入mTasks队列中。然后通过scheduleNext一个接一个的取出来,从这里我们就可以得知,AsyncTask是串行的执行任务。而SerialExecutor 这个线程池只是给AsyncTask任务排队。真正执行任务其实是THREAD_POOL_EXECUTOR线程池,看下面代码:
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;
}
这里暂时先不讲ThreadPoolExecutor这个类,后续会发一篇针对线程池的文章。再回看THREAD_POOL_EXECUTOR.execute(mActive)这行代码,启动真正的任务执行时,传入mActive,这个是从mTasks中取出来的,也就是说THREAD_POOL_EXECUTOR执行任务时,会执行mFuture.run();mFuture是FutureTask类的实例。
4、我们看下FutureTask中的run方法中做了什么事:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> 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 must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
根据上面代码,我们可以看到FutureTask类的run方法里面获取了一个Callable对象,调用了c.call()执行。而上面AsyncTask的构造函数中,初始化FutureTask对象mFuture时,传入了WorkerRunnable对象mWorker。
突然之间,脑门大开,AsyncTask的执行过程原来这么………剩下两字儿哥们幻想下(^▽^)!
5、到此,我们已经知道了AsyncTask是怎么处理后台任务的了,接下来就是对结果的处理了,看WorkerRunnable的call方法里面做了什么事,也就是在初始化mWorker时,看下面代码:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
重新复制了构造函数的代码,大家就不用翻上去看了。不用说谢谢(^▽^)!
在call方法中执行doInBackground时返回一个result,然后 postResult(result);
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封装在AsyncTaskResult中,通过handler发送消息至handleMessage中处理。getHandler()返回的是,已经在构造函数中初始化好的mHandler;
6、接下来再看下mHandler的初始化过程:
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
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:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//更新任务进度
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
根据上面的代码,我可以看到,最终的结果是在AysncTask的finish方法中完成的。一起看看finish里面的代码:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在这里通过isCancelled()判断当前AsyncTask的任务是否已经取消,如果没有,则通过onPostExecute()处理相应结果。
AsyncTask的执行过程到这里已经基本完毕了。这时我们应该知道为什么要在主线程里面去创建AsyncTask对象,并调用execute了。这次分析的AsyncTask是源码6.0以上的,对于一些低版本的会有区别,在这方面网上已经有好多博客有写,这里就不在赘述。关于AsyncTask在开发中的一些缺陷和需要注意的问题:在这里给大家提供一个链接,点击这里