AsyncTask
为了能更加方便的在子线程完成一些耗时操作,然后把结果带到 UI
线程更新页面,Google 使用 Thread
和 Handler
封装了 AsyncTask
类,方便开发者调用。
AsyncTask
是一个封装好的轻量级的异步类, 适用于轻量级(几秒内最好)的后台操作,如果运行时间比较长的,建议使用线程池 (ThreadPoolExecutor
)。
接口
public abstract class AsyncTask<Params, Progress, Result> {
// 运行的线程取决于调用execute()方法的线程
// 在执行线程任务前(doInBackground())的调用,一般用来做一些初始化的操作
// 可选择是否重写此方法
@Override
protected void onPreExecute() {
}
// 在子线程中执行
// 接收输入的参数,执行任务中的耗时操作,最后返回线程任务执行的结果
// 必须重写此方法
@Override
protected Result doInBackground(Params... params) {
return null;
}
// 在主线程中执行
// 回调显示线程任务执行的进度,需在doInBackground方法中调用publishProgress方法
// 可选择是否重写此方法
@Override
protected void onProgressUpdate(Progress... progresses) {
}
// 在主线程中执行
// 接收线程任务执行完后返回的结果
// 必须复写
@Override
protected void onPostExecute(Result result) {
}
}
基本使用
AsyncTask
是一个抽象类,所以需要实现一个继承它的子类。
使用步骤:
- 继承
AsyncTask
实现一个子类 - 替换参数
把AsyncTask<Params, Progress, Result>
的三个参数替换成具体的参数类型,如:AsyncTask<String, Integer, String>
。 - 重写相应的方法
- 创建一个子类的对象
- 调用对象的
execute()
开始执行异步线程任务
// 自定义AsyncTask,static 是为了防止内存泄漏
private static class MyAsyncTask extends AsyncTask<String, Integer, String> {
// 运行的线程取决于调用execute()方法的线程
// 在执行线程任务前(doInBackground())的调用,一般用来做一些初始化的操作
// 可选择是否重写此方法
@Override
protected void onPreExecute() {
System.out.println("onPreExecute thread:" + Thread.currentThread());
}
// 在子线程中执行
// 接收输入的参数,执行任务中的耗时操作,最后返回线程任务执行的结果
// 必须重写此方法
@Override
protected String doInBackground(String... params) {
System.out.println("doInBackground thread:" + Thread.currentThread());
for (int i = 1; i <= 10; i ++) {
publishProgress(i * 10);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "result";
}
// 在主线程中执行
// 回调显示线程任务执行的进度,需在doInBackground方法中调用publishProgress方法
// 可选择是否重写此方法
@Override
protected void onProgressUpdate(Integer... progresses) {
System.out.println("onProgressUpdate progress:" + progresses[0] + ", thread:" + Thread.currentThread());
}
// 在主线程中执行
// 接收线程任务执行完后返回的结果
// 必须复写
@Override
protected void onPostExecute(String result) {
System.out.println("onPostExecute result:" + result + ", thread:" + Thread.currentThread());
}
// 将异步任务设置为取消时调用
// 可选择是否重写此方法
@Override
protected void onCancelled() {
System.out.println("onCancelled thread:" + Thread.currentThread());
}
}
private MyAsyncTask mAsyncTask;
mAsyncTask = new MyAsyncTask();
//调用execute方法开始执行
mAsyncTask.execute("MyAsyncTask");
Log输出
I/System.out: onPreExecute thread:Thread[MyHandlerThread,5,main]
I/System.out: doInBackground thread:Thread[AsyncTask #1,5,main]
I/System.out: onProgressUpdate progress:10, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:20, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:30, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:40, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:50, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:60, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:70, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:80, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:90, thread:Thread[main,5,main]
I/System.out: onProgressUpdate progress:100, thread:Thread[main,5,main]
I/System.out: onPostExecute result:result, thread:Thread[main,5,main]
源码分析
AsyncTask
是对 Handler
和线程池的封装,所以后台任务是通过线程池实现的,然后通过 Handler
把数据带到 UI
线程。
源码分析会结合上面的示例调用的顺序跟进。
1. 初始化流程
mAsyncTask = new MyAsyncTask();
在创建 AsyncTask 时,会调用 AsyncTask 构造方法。
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
//由传入的callbackLooper为空,所以mHandler是用的getMainHandler()返回的Handler,是一个UI线程的Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//初始化一个工作Runnable
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;
}
};
// 把工作 runnable 封装成 future
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);
}
}
};
}
getMainHandler() 的具体实现:
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
// 这里Looper指定使用的MainLooper
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;
}
}
}
由上面源码可以看到,初始化时,主要初始化了 Handler
对象,初始化了派生自 WorkRunnable
类的对象 mWorker
,然后把 mWorker
封装成一个 Future
对象。
而线程池的初始化,这里使用的是一个静态块。
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;
}
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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);
}
}
}
2. 执行任务
mAsyncTask.execute("MyAsyncTask");
在初始化工作完成后,调用 execute()
开始执行任务。
先看一下 execute()
代码:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// 这里的sDefaultExecutor就是线程池,params是我们传入的参数,如上面的 "MyAsyncTask"
return executeOnExecutor(sDefaultExecutor, params);
}
然后继续往下看一下 executeOnExecutor()
方法:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 会先判断一下状态,如果正在执行任务或者任务已经执行完了,会抛出异常,这也是为什么execute()方法只能执行一次的原因
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)");
}
}
// 把任务的状态设置为 RUNNING
mStatus = Status.RUNNING;
// 后台任务开始前,先调用onPreExecute()方法
onPreExecute();
// 把传入的参数设置给初始化好的工作Runnable
mWorker.mParams = params;
// 把mFuture交给线程池执行任务
exec.execute(mFuture);
return this;
}
exec.execute(mFuture); 之后,会调用到 mWorker
的 Call()
方法:
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
// 这里调用doInBackground() 执行后台任务
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
// 处理doInBackground() 执行后台任务得到的结果
postResult(result);
}
return result;
}
};
postResult(result) 方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// getHandler() 得到的是初始化的 mHandler,这里直接把结果交给 Handler 处理
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
Handler 中消息的处理:
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
// 这里的result.mTask就是我们的AsyncTask
switch (msg.what) {
// 任务执行完后,结果处理,进一步调用 finish() 方法
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
// 调用 onProgressUpdate() 方法更新进度
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
finish() 方法:
private void finish(Result result) {
if (isCancelled()) {
// 如果任务已经调用了 cancel 方法结束掉了,会调用 onCancelled 方法
onCancelled(result);
} else {
// 如果任务正常执行完,调用 onPostExecute() 方法
onPostExecute(result);
}
// 最后把状态设置为 FINISHED
mStatus = Status.FINISHED;
}
对于在 doInBackground() 中调用 publishProgress() 方法更新进度,可以看一下 AsyncTask
中的 publishProgress() 方法:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可见,调用 publishProgress() 后,也是通过 Handler
来处理的。
到此,整个调用过程就结束了。
怎么合理取消任务
AsyncTask
提供了 cancel() 方法来取消任务,但是从这个方法的注释中,可以看出几点问题:
- 调用了 cancel() 方法后,会尝试去关闭任务,但是不一定会成功的。
如果任务还未开始执行,取消能成功。
如果任务已经开始执行,能否取消成功取决于线程池。 - 调用 cancel() 后,doInBackground() 方法执行完后会调用 onCancelled() 方法,而不再调用 onPostExecute()。
为了能尽快尽可能地取消掉任务,应该:
- 尽可能早的调用 cancel() 方法。
- 在 doInBackground() 方法中尽可能多的去调用 sCancelled() 判断是否已经 cancel() 任务了,如果是,break 掉后面的执行,直接返回。
总结
-
AsyncTask
不会随着Activity
的销毁而销毁,直到doInBackground()
方法执行完毕。
所以,我们需要在销毁Activity
前取消任务。 -
非静态内部类会持有外部类的引用,也就是在
Activity
中实现的非静态内部类AsyncTask
会持有Activity
的引用。如果Activity
被销毁了,AsyncTask
的后台任务还在执行,它将继续在内存里保留这个引用,导致Activity
无法被回收,引起内存泄露。
所以,AsyncTask
应尽量声明为静态的内部类,防止内存泄漏。
网友评论