大家都知道,使用AsyncTask类,可以很方便的从子线程切换到UI线程。我们今天从源码来了解一下它的原理。
AsyncTask是一个抽象类,我们先看看AsyncTask里面的四个方法:
onPreExecute()(不必重写)
在doInBackground方法之前执行,用于执行一些初始化操作,如显示一个等待框。doInBackground(Params...)(必须重写)
主要处理一些耗时操作,在子线程运行。执行过程中可以用publishProgress更新UI,如更新进度。使用publishProgress会执行onProgressUpdate方法(需要我们重写)。onProgressUpdate(Progress...)(不必重写)
在doInBackground内使用publishProgress方法会执行此处代码,可以用于更新UI。onPostExecute(Result)(不必重写)
doInBackground执行完之后就会调用这个方法,我们可以根据doInBackground返回的数据,进行UI操作。
以上是AsyncTask比较重要的方法,掌握了它,你能很好的应用这个AsyncTask类。但是身边的朋友都不推荐使用,最后我会解释一下为什么。我们先跟着源码了解一下这个类。
我们look两眼构造函数:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();
postResultIfNotInvoked(result);
} 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);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing " + "doInBackground()", t);
}
}
};
}
很简单,只是初始化了mWorker和mFurure两个参数。
如果我们要启动一个任务,我们需要执行execute(Params...)方法,我们look这个方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
接着看executeOnExecutor方法:
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();
// 这里其实是doInBackground(Params...)的参数
mWorker.mParams = params;
// 执行后台任务
exec.execute(mFuture);
return this;
}
我们先解释一下sDefaultExecutor这个值,因为要了解 exec.execute(mFuture),我们的先知道exec,即sDefaultExecutor的值。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
我们继续追下去,看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);
}
}
}
因为调用了exec.execute(mFuture)这个,对照源码,参数r就是我们的mFuture了,mFuture执行了run方法,这个run方法其实是调用了innerRun方法,我们直接看到innerRun这个方法:
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) {
// recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
callable是个什么鬼?其实就是我们构造函数传进来的mWorker。看到构造函数,call()方法中调用了postResult(doInBackground(mParams)),这就调用了我们重写的doInBackground(mParams)了。我们可以look一下postResult这个方法:
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
这里就是把获取的结果,通过handler机制,把result发用到UI线程处理。我们可以看看这个自定义的hander长咋样:
private static class InternalHandler extends Handler {
@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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
到这里,我们之前说的4个重要的方法也都全部调用了。还有一个方法的实现,就是在用于在doInBackground方法里通知更新UI的publishProgress,代码:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
从源码可以知道,也是通过handler来更新UI的。
以上是AsyncTask整个源码的分析。我之前说过,身边很多朋友都不推荐使用这个类,因为啥呢??我来解释一下。
生命周期不稳定
大家都以为,我创建了一个AsyncTask,等Activity销毁会自动销毁,我们不用care。并非如此,如果activity销毁时,正在子线程执行耗时任务,那么子线程会继续do下去。如果我们不去手动cancel()它的话,doInBackground()会把结果通过handler发送到UI处理,可是UI已经销毁(为空)了,这时会报crash。
再有,我们旋转屏幕的时候,他会重新去创建,又会重新执行一遍,这样会浪费资源,还取消不掉。内存泄露
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。这个Handler泄露差不多一样。因为Activity要销毁了,此时AsyncTask还在执行子线程耗时操作,还是持有Activity的引用,这样Activity无法被回收。
以上也就大神们不推荐使用这个类的原因。还能用吗??看你怎么使用咯。我在这里推荐使用rxjava代替AsyncTask,这个开源框架可以不但可以帮我们很好的解决问题,还给我们带很多方便。这个框架我以后我也会总结。