Android AsyncTask工作原理分析
闲来无事又看了一下android多线程的部分源码,由于自己经常会忘记一些知识,用博客记录一下,也算加强记忆,同时也分享自己的一些理解,以此来相互学习。本文源码主要基于android 8.0,也就是api26,如发现版本不一致的,可切换到该版本下,查看。
- 一、AsyncTask概述
- 二、AsyncTask的工作流程
一、AsyncTask概述
1.1 类的介绍和使用
AsyncTask是一个轻量级的异步任务类,我们看一下它的声明
public abstract class AsyncTask<Params, Progress, Result> {
它是一个抽象类,所以我们平时使用时,先继承它,用子类去实现和重载它相关的方法。
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
1.2主要方法介绍
由于它是抽象类,我们继承后主要实现和重载了3个抽象方法:
onPreExecute():在主线程中执行,在异步任务执行之前执行,主要用来做一些准备工作。
doInBackground(Params… params):在子线程中执行,params为异步任务的输入参数。
onPostExecute(Result result):在主线程中执行,异步任务执行后,调用此方法,result为执行后的结果数据的返回。
除此之外,我们经常还会用到的,还有:
onProgressUpdate(Progress… values) :在主线程中执行,子线程任务进度发生变化时被调用,通常用来更新进度条。
这些方法的调用顺序依次为onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)
二、AsyncTask的工作流程
我们继承这个类和实现后,主要使用如下:
new DownloadFilesTask().execute(url1, url2, url3)
先new了这个类,然后执行了它的execute方法;那我们先从它的构造函数进行分析:
2.1构造函数
我们先看一下构造函数的源码,构造函数主要有3个。
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
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);
}
}
};
}
从构造中可以看出,它主要做了3个方面的工作:
(1)获取一个主线程的Handler,来初始化mHandler ,如果没有形参callbackLooper是空,或者callbackLooper 是主线程的Looper,就通过getMainHandler(),来初始化;否则,就直接new Handler(callbackLooper)。
getMainHandler()里面又做了什么工作呢?
看一下它的源码:
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
它主要是构造了一个单例的sHandler返回给mHandler;在这里我们看到new的是一个InternalHandler,它里面又是什么呢?
我们再看一下InternalHandler的源码:
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;
}
}
}
它是一个静态内部类,主要实现了handleMessage的方法,handleMessage中主要对2类消息进行了处理,一类是MESSAGE_POST_RESULT消息,接收到这个消息后finish了当前的的任务,这里主要可以看result.mTask,不详细介绍;另一类消息是MESSAGE_POST_PROGRESS,接收到这个消息后主要执行了当前任务的onProgressUpdate方法,更新进度。
(2)再回构造函数,执行完Handler的初始化,然后new了一个继承WorkerRunnable的匿名内部类赋值给mWorker;WorkerRunnable是一个静态抽象内部类
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
从这里可以看出,WorkerRunnable是一个静态抽象内部类,大家都知道抽象类不能直接被实例化的,所以这里它使用了匿名内部类的方式进行对mWorker进行实例化,刚开始还觉得有点别扭。
同时,我们也看到它继承了Callable接口,并且在实例化时,实现了call方法。
(3)再回构造函数,对mFuture进行了实例化,重载了done()方法,在done()里面主要调用了postResultIfNotInvoked(Result result)这一方法,我们打开这个方法的源码
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
从中可以看出,它又调用了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只是负责发消息;然后mHandler接收和处理消息,这就和前面对应上了。
好了构造函数看完了,我们接下来看execute方法,看到这里其实还是迷糊的。当我们看完execute就不觉得迷糊了,思路就开始清晰了。
2.2execute方法分析
我们还是直接打开源码
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方法里先确定了当前任务的状态,然后调用了onPreExecute(),这里就执行到我们的任务前准备的方法了,然后又执行了exec.execute(mFuture);exec我们入参的是sDefaultExecutor对象,这个sDefaultExecutor是被一个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);
}
}
}
可以看出SerialExecutor主要是做了排队,通过线程池THREAD_POOL_EXECUTOR执行mActive任务,我们任务开始执行后,又到了哪里呢?我们看到mActive是从mTasks.poll()来得,mTasks又在mTasks.offer的Runnable的匿名对象中执行了run方法中的r.run(),这个r是我们在executeOnExecutor方法的exec.execute(mFuture)语句中传入的mFuture对象。mFuture我们在构造函数中进行了实例化。
这里很重要
当mActive任务呗执行时,run方法被回调,根据入参可知道实际上是mFuture的run()方法就会执行,mFuture是被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);
}
}
从中我们可以看到result = c.call();c的call方法被调用了,c是什么呢?c就是入参的mWorker对象,call()方法就是在AsyncTask的构造函数里mWorker被实例化时的实现的那个方法,这里mFuture就和mWorker完全关联起来了
call()方法被调用时,执行了result = doInBackground(mParams);从这一段可以看到,我们的doInBackground方法也被执行了。执行完后,postResult将会被执行,发送了一个msg.what为MESSAGE_POST_RESULT的消息,
mHandler接收到MESSAGE_POST_RESULT消息后,执行了
result.mTask.finish(result.mData[0]);这里就调用了mTask的finish方法,我们看一下finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
finishi方法,判断了,是否可以取消,不能取消时就执行onPostExecute方法。可取消时执行onCancelled方法。这里可以看到任务可以被取消,当我们经常离开activity时,任务没执行完时,可以取消掉。
我们的任务到这里就走完了。有人说我们的的更新进度方法还没执行呢?我们可以看到api里面有提供一个publishProgress的方法,我们可在实现doInBackground方法中,多次调用publishProgress方法,发送MESSAGE_POST_PROGRESS消息,当我们的mHandler接收到该消息就会回调onProgressUpdate方法,我们重载的onProgressUpdate方法就被调用了,就可以在主线程中更新进度条了。
到这里我们的流程就完全清楚了。
execute流程
好了,分享到这里就结束了,感谢细心看完,如果有不理解的可以私信我。谢谢大家!