本文作者:CodingBlock 文章链接:https://cloud.tencent.com/developer/article/1351742
AsyncTask是一种轻量级的异步任务类,可以很方便的在线程池中执行异步任务,并且将进度和结果传递给主线程。其底层由Thread+handler实现。
AsyncTask是一个抽象的泛型类,其类的声明如下:
public abstract class AsyncTask<Params, Progress, Result>
其中三个泛型参数代表的意义如下:
在使用AsyncTask执行异步任务需要创建一个类,让这个类继承AsyncTask,并实现相关方法,具体形式如下,在下面代码中实现了几个重要的方法,每个方法代表的意义可以见注释:
/**
* Created by liuwei on 18/2/28.
*/
public class MyAsyncTask extends AsyncTask<String, Integer, String> {
/**
* 在异步任务执行之前调用
* 执行在主线程中
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 执行异步任务
* 执行在线程池中
* @param params
* @return
*/
@Override
protected String doInBackground(String... params) {
return null;
}
/**
* 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
/**
* 当异步任务执行进度改变时执行此方法
* 执行在主线程中
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* 当异步任务执行完成后执行此方法
* 执行在主线程中
* @param s
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
要注意的时,需要在doInBackground方法中调用publishProgress()发送任务执行进度,onProgressUpdate才能被回调。
执行AsyncTask是需要在主线程中调用:
new MyAsyncTask().execute();
在使用AsyncTask时有一些限制我们要注意:
接下类使用AsyncTask,借助循环模拟一个耗时任务的小例子,还是用上面的MyAsyncTask类,并在其相关方法上面添加一些辅助代码,详细代码如下:
public class MyAsyncTask extends AsyncTask<String, Integer, String> {
private final static String TAG = MyAsyncTask.class.getSimpleName();
private int taskSize = 10;
/**
* 在异步任务执行之前调用
* 执行在主线程中
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "onPreExecute: ");
}
/**
* 执行异步任务
* 执行在线程池中
* @param params
* @return
*/
@Override
protected String doInBackground(String... params) {
Log.i(TAG, "doInBackground: ");
int i;
for (i = 0; i < taskSize; i++) {
SystemClock.sleep(1000);
int progress = (int)((i / (float)taskSize) * 100);
publishProgress(progress);
if (isCancelled()) {
break;
}
}
return "执行结果:" + (i / (float)taskSize) * 100 + "%";
}
/**
* 当异步任务被取消时执行此方法,此时将不会再调用onPostExecute方法
*/
@Override
protected void onCancelled() {
super.onCancelled();
Log.i(TAG, "onCancelled: ");
}
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
Log.i(TAG, "onCancelled: result=" + s);
}
/**
* 当异步任务执行进度改变时执行此方法
* 执行在主线程中
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i(TAG, "onProgressUpdate: 执行进度:" + values[0] + "%");
}
/**
* 当异步任务执行完成后执行此方法
* 执行在主线程中
* @param s
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.i(TAG, "onPostExecute: result=" + s);
}
}
在Activity中调用new MyAsyncTask().execute();执行Log如下:
.../cn.codingblock.thread I/MyAsyncTask: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: onPostExecute: result=执行结果:100.0%
我们稍加改造一下上面的示例,在构造方法中传入一个taskId,然后在关键log中输出这个taskId,以便于区分:
private int taskId;
public MyAsyncTask(int taskId) {
this.taskId = taskId;
}
/**
* 在异步任务执行之前调用
* 执行在主线程中
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "taskId= " + taskId + ": onPreExecute: ");
}
// 其他方法类比onPreExecute方法中的log增加taskId,就不贴出了
在Activity中初始化两个AsyncTask对象,并调用excute执行任务:
public class AsyncTaskActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
MyAsyncTask task1 = new MyAsyncTask(1);
MyAsyncTask task2 = new MyAsyncTask(2);
task1.execute();
task2.execute();
}
}
log如下:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0%
可以看到两个任务是串行执行的。
AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params)
executorOnExecutor方法有两个参数,第一个是Executor,第二个是任务参数。
第一个参数有两种类型:
在执行task2时调用executeOnExecutor,观察执行结果:
public class AsyncTaskActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
MyAsyncTask task1 = new MyAsyncTask(1);
MyAsyncTask task2 = new MyAsyncTask(2);
task1.execute();
task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
log如下:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPreExecute:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: doInBackground:
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:10%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:20%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:30%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:40%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:50%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:60%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:70%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:80%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 2: onPostExecute: result=taskId= 2: 执行结果:100.0%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onProgressUpdate: 执行进度:90%
.../cn.codingblock.thread I/MyAsyncTask: taskId= 1: onPostExecute: result=taskId= 1: 执行结果:100.0%
从log可以看到,两个任务在并发执行。
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@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)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
我们需要了解的是,一个AsyncTask任务有三种状态:PENDING(未开始)、RUNNING(运行中)、FINISHED(已完成)。
从上面源码我们可以看到,一个AsyncTask实例任务只能运行一次,只有是在PENDING状态下,任务才能正常运行,否则就会抛出异常。
接着在执行任务前先调用了onPreExecute方法,并将参数赋值给mWorker的参数数组,然后使用exec执行在AsyncTask初始化阶段封装好的mFuture。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new 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);
}
}
}
从源码可以进一步看出,sDefaultExecutor是SerialExecutor对象,是一个串行的线程池,同一个进程中的所有的AsyncTask任务都在这个线程池中排队执行。
SerialExecutor的execute方法首先会将FutureTask任务加入到mTasks队列中,此时如果没有正在活动的任务就会调用scheduleNext执行下一个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);
}
}
};
}
WorkerRunnable的call方法中的代码很好理解,首先调用了mTaskInvoked.set(true),将任务的设为已调用状态。接着调用了doInBackground方法并获取了返回值,然后将返回值传递给postResult()方法,再看postResult方法的源码如下:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));// 在这里将doInBackground的返回结果result封装到AsyncTaskReuslt对象里面通过handler发送给主线程
message.sendToTarget();
return result;
}
在此方法中通过handler发送了一条MESSAGE_POST_RESULT的消息。此handler的相关代码如下(为方便查看,适当调整了代码顺序):
private final Handler mHandler;
private Handler getHandler() {
return mHandler;
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null); // 在这里传入了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); // 根据上一步调用可知,handler为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() // 根据上一步调用可知,callbackLooper为null,在此会调用getMainHandler()
: new Handler(callbackLooper);
...
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
private static InternalHandler sHandler;
在上面的源码中可知,最终getHandler()方法最终是为sHandler,而sHandler是一个静态的Handler对象,sHandler的作用是将执行环境切换到主线程中,所以这就要求sHandler要在主线程中被初始化,而由于静态成员会在类加载时被初始化,这就又要求了AsyncTask类必须在主线程中加载,否则该进程中的AsyncTask任务都无法正常工作。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]); // 调用AsyncTask的finish方法。
break;
...
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result); // 如果任务被取消了就去调用onCancelled方法。
} else {
onPostExecute(result); // 任务完成后就将执行结果传递给onPostExecute方法
}
mStatus = Status.FINISHED; // 最后将状态置为FINISHED
}
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() { // 1、在执行完mWorker的call方法之后会执行done方法。2、或者在FutureTask任务被取消后也会执行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); // 在Future任务被取消时,在此段代码中就会抛出CancellationException异常,即会执行此方法。
}
}
};
我们知道Future被执行后,会调用传入的mWorker的call方法,在执行完mWorker的call方法之后或者FutureTask被取消时会调用done方法,我们看到源码中在done方法中调用postResultIfNotInvoked():
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
在这个方法中可以看到,只有当wasTaskInvoked为false是才会发送结果,也就是说,这一步是在WorkerRunnable任务未被执行并取消的情况下才发送结果给主线程,在前几步中我们就已经知道了postResult()方法中的调用过程,最终会调用到finish方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result); // 如果任务被取消了就去调用onCancelled方法。
} else {
onPostExecute(result); // 任务完成后就将执行结果传递给onPostExecute方法
}
mStatus = Status.FINISHED; // 最后将状态置为FINISHED
}
在任务被取消的情况下回调了onCancelled方法,至此AsyncTask异步任务执行流程基本分析完了。
最后简单总结一下AsyncTask的原理:
最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!
参考文献:
本文作者:CodingBlock 文章链接:https://cloud.tencent.com/developer/article/1351742