走向异步处理AsyncTask
1.AysncTask的三个核心
首先我要说的是网上有很多关于AysncTask的文章,这里我就不累赘重复做过多的基本介绍QAQ,所以我就从侧面阐述我对AysncTask的一些认识。
我们都知道Android官方为了让创建异步任务更简单,把Handler和Thread封装成AysncTask。
所谓三核心,就是三个核心方法:
- doInBackground(Params… params):继承AysncTask必须重写的一个抽象方法,此方法执行在AysncTask维护的一个线程池中,所以可以在这个方法中做一些耗时操作。
- onProgressUpdate(Progress… values):执行在主线程中,在doInBackground中调用publishProgress时,执行此方法,可以在主线程更新ui。
- onPostExecute(Result result):执行在主线程,doInBackground结束时调用这个方法。
2.走进AysncTask
AysncTask从execute开始执行:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//execute又会调executeOnExecutor
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先执行
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
忽略复杂的部分,可以知道在execute的时候最先调用的是onPreExecute方法,所以可以在这里面做一些初始化的操作。
看一下,构造方法:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
在构造方法中对mWorker和mFuture 初始化,mFuture会调用mWork的call方法,那么call方法执行在线程池,mWork的call方法执行了doInBackground,那么doInBackground也执行在线程池。
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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处理MESSAGE_POST_RESULT消息执行finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
在finish方法中会调用onPostExecute,整个工作流程就差不多了。
3.AysncTask的使用思想
一般的我们可以new一个子线程然后通过handler来更新ui,那为什么还用使用AysncTask呢?
想象一台机器,通过Thread和handler就像打开机器内部修改各种零件,这种方法对于整个过程的控制比较精细,通过AysncTask就像坐在控制台指挥机器工作一样,使得异步创建更加简单,代码不会相对臃肿。
但是AysncTask并不适合进行特别耗时的操作,在更新UI特别是大量的itemview的时候也不是很给力。
线程池是异步操作的重要方式,但是自行实现一个线程池并不容易,因为你需要解决死锁,资源分配,wait和notify等复杂问题,因此Android官方为我们封装的AysncTask使我们更容易实现轻量级,简单的自定义异步类。
下面是几点需要注意的:
AysncTask的对象必须在主线程中创建,execute方法必须在ui线程中调用。
一个AysncTask对象只能执行一次,只能调用一次execute方法,否则报错。
在Android3.0之后,为避免并发错误AysncTask采用一个线程串行执行任务。
不能在doInBackground中更新ui,也不要在onPostExecute中大量更新ui。