1 AsyncTask的基本使用
public abstract class AsyncTask<Params, Progress, Result>
-
Params:启动任务执行的输入参数,如http请求的url
-
Progress:后台任务执行的百分比
-
Result:后台执行任务最终返回的结果类型
对应参数不处理设置成Void
public class DownLoadAsyncTask extends AsyncTask<String,Integer,Bitmap> {
/**
* onPreExecute是可以选择性覆写的方法
* 在主线程中执行,在异步任务执行之前,该方法将会被调用
* 一般用来在执行后台任务前对UI做一些标记和准备工作,
* 如在界面上显示一个进度条。
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 抽象方法必须覆写,执行异步任务的方法
* @param params
* @return
*/
@Override
protected Bitmap doInBackground(String... params) {
return null;
}
/**
* onProgressUpdate是可以选择性覆写的方法
* 在主线程中执行,当后台任务的执行进度发生改变时,
* 当然我们必须在doInBackground方法中调用publishProgress()
* 来设置进度变化的值
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* onPostExecute是可以选择性覆写的方法
* 在主线程中执行,在异步任务执行完成后,此方法会被调用
* 一般用于更新UI或其他必须在主线程执行的操作,传递参数bitmap为
* doInBackground方法中的返回值
* @param bitmap
*/
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
}
/**
* onCancelled是可以选择性覆写的方法
* 在主线程中,当异步任务被取消时,该方法将被调用,
* 要注意的是这个时onPostExecute将不会被执行
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
}
启动AsyncTask:
new DownLoadAsyncTask().execute();
AsyncTask在具体的使用过程中也是有一些条件限制的,主要有如下几点:
-
AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1及以上版本中已经被系统自动完成。在Android 5.0的源码中,可以查看
ActivityThread
的main
方法,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了 -
AsyncTask的对象必须在主线程中创建
-
execute()
必须在UI线程调用 -
不要在程序中直接调用
onPreExecute()
、onPostExecute()
、doInBackground()
和onProgressUpdate()
-
一个AsyncTask对象只能执行一次,即只能调用一次
execute()
,否则会报运行时异常 -
在Android 1.6之前,AsyncTask是串行执行任务,Android 1.6的时候AsyncTask开始采用线程池处理并行任务,但是从Android 3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用了一个线程来串行执行任务。尽管如此,在Android 3.0以及后续版本中,仍然可以通过AsyncTask的
executeOnExecutor()
来并行执行任务
3 AsyncTask工作原理
为了能够更清晰的理解AsyncTask的工作原理,在分析原理之前,有必要对AsyncTask的内部构造做一个简单的说明。
我们知道AsyncTask能在 doInBackground()
执行耗时操作,其中耗时操作会由内部的一个线程池 THREAD_POOL_EXECUTOR
处理, onProgressUpdate()
、onPostExecute()
切回主线程更新UI,而切换回UI线程是通过Handler收发消息实现的。
从 execute()
开始分析,execute()
会调用 executeOnExecutor()
:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// sDefaultExecutor是一个串行的线程池
// 一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
case FINISHED:
// 抛异常
break;
}
}
mStatus = Status.RUNNING;
onPreExecute(); // 在执行耗时操作前就回调onPreExecute()
mWorker.mParams = params; // WorkerRunnable的call()方法会在线程池中执行回调doInBackground()
exec.execute(mFuture); // FutureTask,在构造中会传入在线程池执行耗时任务的mWorker
return this;
}
接下来分析线程池的执行过程:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// SerialExecutor线程池用于任务的排队,实际执行的线程池是THREAD_POOL_EXECUTOR
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();
Runnable mActive;
// 在AsyncTask.executorOnExecutor()中的sDefaultExecutor.execute()调用该方法
// 传入的是AsyncTask的Params参数封装的FuterTask对象,是一个并发类充当Runnable
public synchronized void execute(final Runnable r) {
// 将Runnable存到队列中
mTasks.offer(new Runnable() {
public void run() {
try {
// 从这里可以看出在一个AsyncTask任务执行完后才去拿下一个AsyncTask任务
// 调用FuterTask的run(),实际是调用的内部WorkerRunnable的call()
r.run();
} finally {
scheduleNext(); // 执行下一个AsyncTask任务
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
// 从队列中拿一个AsyncTaskr任务扔给线程池执行
if ((mActive == mTasks.poll()) != null) {
// 实际的耗时操作是在线程池THREAD_POOL_EXECUTOR执行
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
FutureTask
的 run()
会调用 mWorker
的 call()
方法,因此 mWorker
的 call()
最终会在线程池中执行,在AsyncTask构造方法中:
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true); // 设置标志表示当前任务已经被调用了
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};
mFuter = new FuterTask<Result>(mWorker) {...}
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget(); // 将doInBackground()的执行结果通过Handler发送切换回主线程更新UI
return result;
}
private static final InternalHandler sHandler = new InternalHandler();
// 在线程池中获取的数据通过Handler从子线程切换回主线程更新UI
// InternalHandler是静态成员在加载类的时候会初始化,因此这就要求AsyncTask必须在主线程中加载
private static class InternalHandler extends Handler {
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]); // 回调AsyncTask的finish
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result); // 回调结果
}
mStatus = Status.FINISHED;
}
// FutureTask内部
public FutureTask(Runnable runnable) {
this.callable = callable;
this.state = NEW;
}
public void run() {
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
try {
result = c.call(); // 调用的是WorkerRunnable的call()
} catch (Throwable ex) {...}
}
} finally {...}
}