迁移自CSDN菜鸟看源码之AsyncTask
首先扯点别的:今天是第二天上班,看了看日历已经是2月23号了,2018年还剩9个多月。真是感觉人生如白驹过隙啊。今年自己竟然不知不觉已经26周岁了,趁着还算比较年轻(再过个3,4年这话就不好说了),努力奋斗!
今天梳理一下AsyncTask的源码
基于源码8.0
这部分文字叙述摘抄自郭霖老师的博客 Android AsyncTask完全解析,带你从源码的角度彻底理解
先看基本的使用方法:由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:
- Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
- Progress:后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
- Result:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
继承AsyncTask通常需要重写下面几个方法
- onPreExecute():这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
- doInBackground(Params...):这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。
- onProgressUpdate(Progress...):当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
- onPostExecute(Result):当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
以下载一个文件为例
新建DownloadTask类继承AsyncTask
static class DownloadTask extends AsyncTask<String, Integer, Boolean> {
private final String TAG = getClass().getName();
@Override
protected void onPreExecute() {
Log.d(TAG, "onPreExecute: showDialog");
}
@Override
protected Boolean doInBackground(String... strings) {
String url = strings[0];
try {
while (true) {
int percent = doDownload(url);
//发布进度
publishProgress(percent);
if (percent >= 100) {
//下载完成
break;
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
//设置进度
Log.d(TAG, "onProgressUpdate: progress=" + progress);
}
@Override
protected void onPostExecute(Boolean success) {
Log.d(TAG, "onPostExecute: dismissDialog");
if (success) {
Log.e(TAG, "success");
} else {
Log.e(TAG, "failed");
}
}
//模拟下载的方法
private int doDownload(String url) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 100;
}
}
使用
private DownloadTask downloadTask;
downloadTask = new DownloadTask();
downloadTask.execute("http://blog.csdn.net/u011240877/article/details/72905633");
如果要取消正在执行的任务
if (!downloadTask.isCancelled()) {
downloadTask.cancel(true);
}
源码分析
首先先看一下AsyncTask的构造函数,必须在主线程调用
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
//注释1处
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//注释2处
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;
}
};
//注释3处
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);
}
}
};
}
在注释1处,为mHandler赋值,mHandler是一个Handler类型的对象。因为我们传入的Looper对象是null,所以会调用getMainHandler方法为mHandler赋值。
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
//传入的Looper对象是主线程的Looper对象
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
方法返回的是一个InternalHandler对象。并且返回的InternalHandler对象是和主线程的Looper对象关联的。这也是为什么onProgressUpdate
方法和onPostExecute
方法在主线程执行的原因。
在注释2处为mWorker赋值,mWorker是一个WorkerRunnable对象。WorkerRunnable是AsyncTask的静态内部类,它是一个抽象类。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
//保存要执行的任务的参数
Params[] mParams;
}
注意WorkerRunnable是实现了Callable接口的。当WorkerRunnable被执行的时候,它的call
方法会被调用并返回执行结果。
在注释3处使用mWorker对象为mFuture赋值,mFuture是一个FutureTask对象。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
//开始FutureTask的状态是NEW
this.state = NEW;
}
好了,构造函数先看到这里,接下来我们看一看AsyncTask的 execute方法。
//execute方法要在主线程调用
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//内部调用executeOnExecutor方法
return executeOnExecutor(sDefaultExecutor, params);
}
调用executeOnExecutor方法
@MainThread
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)");
}
}
//AsyncTask的任务状态初始化为RUNNING
mStatus = Status.RUNNING;
//注释1处
onPreExecute();
//注释2处
mWorker.mParams = params;
//注释3处执行任务
exec.execute(mFuture);
//返回AsyncTask对象本身用于取消任务
return this;
}
在上面的代码中可以看到,注释1处最先执行的是 onPreExecute
方法。
然后在注释2处为mWorker的mParams
赋值。
注释3处,这里要注意一下,开始执行任务 exec.execute(mFuture);
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
}
当我们调用AsyncTask的execute(Params... params)
方法的时候,内部会调用executeOnExecutor(Executor exec, Params... params)
方法,传入的exec
参数就是AsyncTask默认的 sDefaultExecutor
。
我们也可以直接调用AsyncTask的executeOnExecutor(Executor exec, Params... params)
方法并传入我们自定义的一个Executor。就像下面这样:
Executor exec = new ThreadPoolExecutor(15, 200, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
//传入自定义的Executor
new DownloadTask().executeOnExecutor(exec, "downloadUrl");
本篇文章只讨论使用AsyncTask默认执行器的情况。那么接下来我们看看AsyncTask的默认执行器sDefaultExecutor
是何方神圣。
//注释1处
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//按顺序线性执行任务的执行器
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
注释1处注意一下,sDefaultExecutor
是一个静态变量,也就是说应用中的所有AsyncTask实例,都会共用这一个Executor。
SerialExecutor类
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//注释1处将任务加入到mTasks
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
//注释3处
scheduleNext();
}
}
});
//注释2处
if (mActive == null) {
//开始执行任务
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
//注释4处
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
当我们调用 exec.execute(mFuture);
的时候,
首先在注释1,处会把传入的mFuture加入到SerialExecutor的任务队列中。
然后注释2处,如果SerialExecutor中没有正在执行的任务,就调用scheduleNext
方法来从任务队列中取出一个任务,如果任务不为null,就执行该任务。
注释3处,当一个任务执行完毕以后,然后再调用scheduleNext
方法执行下一个任务,从这里我们可以看出AsyncTask默认是顺序执行任务的,每次只有一个任务被执行。
注释4处,使用THREAD_POOL_EXECUTOR
来执行任务.。这个THREAD_POOL_EXECUTOR
是个什么东东,了解一下。
AsyncTask类部分代码
//核心线程池数量
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;
//线程池的任务队列,限制长度为128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
好了,现在我们知道了THREAD_POOL_EXECUTOR
就是一个线程池,负责为我们创建线程来执行任务。当我们调用 THREAD_POOL_EXECUTOR.execute(mActive);
时候,会从线程池中取出一个线程执行mActive的run方法。
SerialExecutor的execute方法
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
//调用传入的Runnable对象的run方法
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
当mActive的run方法执行的时候,会调用传入的Runnable对象的run方法。在上面的分析中可以知道我们传入的Runnable对象r
就是mFuture,是一个FutureTask对象。
接下来看一下mFuture的run方法
public void run() {
//...
try {
//这个callable就是我们传入的mWorker对象。
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//注释1处
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
//注释2处
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);
}
}
在mFuture的run方法的注释1处调用了我们传入的mWorker对象的call方法。再贴一下mWorker对象赋值的代码。
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//注意,这里我们把mTaskInvoked设为了true
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//注释1处
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//注释2处
postResult(result);
}
//注释3处
return result;
}
};
在mWorker的call方法中首先把mTaskInvoked设为了true,然后在注释1处,首先调用了doInBackground开始执行任务。然后在注释2处把执行结果post了出去。我们看一下AsyncTask的postResult方法。
private Result postResult(Result result) {
//发送MESSAGE_POST_RESULT类型的消息
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
在postResult方法内部先调用getHandler获取mHandler对象,然后使用mHandler发送MESSAGE_POST_RESULT类型的消息。在上文的分析中我们知道mHandler是一个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:
// 调用AsyncTask的finish方法。
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
在InternalHandler的handleMessage方法中,如果发送的消息类型是MESSAGE_POST_RESULT的话就调用AsyncTask的finish方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
//将任务的状态置为FINISHED
mStatus = Status.FINISHED;
}
在方法内部,如果任务被取消了,就调用onCancelled方法,否则就调用onPostExecute方法。最后还要把AsyncTask的状态置为FINISHED。其实到这里对用户来说,执行已经结束了。
我们回到在mWorker的call方法的注释3处,返回了执行结果。
然后继续回到接下来看一下mFuture的run方法的注释2处
if (ran)
set(result);
FutureTask的set方法
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
//将FutureTask的状态置为NORMAL
U.putOrderedInt(this, STATE, NORMAL); // final state
//调用finishCompletion方法
finishCompletion();
}
}
private void finishCompletion() {
//...
//调用done方法
done();
//将callable置为null
callable = null;
}
我们看到在finishCompletion方法中调用了done方法,我们在初始化mFuture的时候覆盖了done方法,我们看一下。
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
//注释1处
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);
}
}
};
在上面代码中的注释1处首先调用了FutureTask的get方法获取执行结果,然后调用postResultIfNotInvoked方法。
AsyncTask的postResultIfNotInvoked方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
因为在mWorker的call方法中我们把mTaskInvoked设为了true,所以这里是不会执行的。到此整个分析过程就结束了。
总结:AsyncTask内部还是通过Handler机制来实现线程间通信:内部使用一个Executor执行提交的任务,当需要发布任务的执行进度和返回执行结果的时候,就是用一个主线程的Handler发送消息,然后在主线程进行UI改变。
参考链接
- Android AsyncTask完全解析,带你从源码的角度彻底理解
- 《Android 进阶之光》
网友评论