注册

AsyncTask源码分析

AsyncTask,Android 实现异步方式之一,即可以在子线程进行数据操作,然后在主线程进行 UI 操作


AsyncTask的简单使用


示例


同样的,我们先看看 AsyncTask 如何进行简单使用:


        AsyncTask<Boolean, Integer, String> asyncTask = new AsyncTask<Boolean, Integer, String>() {

@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i("TAG", "onPreExecute:正在执行前的准备操作");
}

@Override
protected String doInBackground(Boolean... booleans) {
Log.i("TAG", "doInBackground:获得参数" + booleans[0]);
for (int i = 0; i < 5; i++) {
publishProgress(i);
}
return "任务完成";
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i("TAG", "onProgressUpdate:进度更新" + values[0]);
}

@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);

Log.i("TAG", "onPostExecute:" + s);
}
};
Log.i("TAG", "开始调用execute");
asyncTask.execute(true);

输出结果:


2020-04-02 17:14:42.029 4995-4995 I/TAG: 开始调用execute
2020-04-02 17:14:42.029 4995-4995 I/TAG: onPreExecute:正在执行前的准备操作
2020-04-02 17:14:42.030 4995-5118 I/TAG: doInBackground:获得参数true
2020-04-02 17:14:45.774 4995-4995 I/TAG: onProgressUpdate:进度更新0
2020-04-02 17:14:45.774 4995-4995 I/TAG: onProgressUpdate:进度更新1
2020-04-02 17:14:45.774 4995-4995 I/TAG: onProgressUpdate:进度更新2
2020-04-02 17:14:45.774 4995-4995 I/TAG: onProgressUpdate:进度更新3
2020-04-02 17:14:45.774 4995-4995 I/TAG: onProgressUpdate:进度更新4
2020-04-02 17:14:45.775 4995-4995 I/TAG: onPostExecute:任务完成

创建说明


首先,在创建 AsyncTask 的时候,需要传入三个泛型数据AsyncTask<Params, Progress, Result>,其分别对应着


   protected abstract Result doInBackground(Params... params);

    @MainThread
protected void onProgressUpdate(Progress... values) {
}

    @MainThread
protected void onPostExecute(Result result) {
}

从注解可以看出,onProgressUpdateonPostExecute是在主线程执行。


执行流程



  • AsyncTask 调用execute(Params... params)方法
  • onPreExecute() 被调用,该方法用于在执行后台操作前进行一些操作,例如:弹出个加载框等
  • doInBackground(Params... params) 被调用,该方法用于进行一些复杂的数据处理,例如数据库操作等
  • doInBackground进行操作的过程中,可以通过publishProgress(Progress... values)进行进度更新,从而自动调用onProgressUpdate(Progress... values)
  • doInBackground执行完毕后,返回数据,将会调用onPostExecute(Result result)

源码分析(源码只保留关键部分,并非全部源码)


AsyncTask创建


    public AsyncTask() {
this((Looper) null);
}

   public AsyncTask(@Nullable Looper callbackLooper) {
//创建Handler,默认使用主线程的 Looper
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);

//后面这段代码看起来有点长,其实就是使用了 Future 模式,
//先建立一个类继承 Callable 接口,再将该类赋值到 FutureTask 中,
//至于 call() 和 done() 方法里面具体内容可以先不用理会
//等 mFuture 被线程调用的时候,就会调用 call()
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
···
return result;
}
};

mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
···
}
};
}

InternalHandler解析


着重看下getMainHandler()


    private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
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;
}
}
}

在创建 InternalHandler 的时候,传入了Looper.getMainLooper(),说明了 InternalHandler 的handleMessage方法可以执行 UI 操作。


我们在仔细看看handleMessage里面有两种处理:


result.mTask.finish(result.mData[0]);


result.mTask.onProgressUpdate(result.mData);

其中,result 即为 AsyncTaskResult<?>


    private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;

AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}

所以result.mTask其实就是 AsyncTask,result.mTask.finish就是调用 AsyncTask 的 finish 方法:


    private void finish(Result result) {
//判断当前 AsyncTask 是否已被取消,已取消则调用 onCancelled,未取消则调用 onPostExecute
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

由此,可以证明onPostExecute在 UI 线程执行


result.mTask.onProgressUpdate(result.mData);就更容易理解了,直接调用onProgressUpdate


    @MainThread
protected void onProgressUpdate(Progress... values) {
}

由此,可以证明onProgressUpdate也在 UI 线程执行


AsyncTask执行


asyncTask.execute(true);


    @MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

// sDefaultExecutor 为线程池
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    @MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//判断当前 AsyncTask 的运行状态,假如运行状态为 RUNNING 或者 FINISHED,则直接报错
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 内部使用了线程池进行线程操作
  • 每个 AsyncTask 对象只能执行一次!!!

???


使用线程池,却一个对象只能执行一次?这两个不是互相矛盾的吗?众所周知,线程池都是为了管理多线程而存在的。


我们再来仔细看下


 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

static volatilestatic final,说明默认实现 AsyncTask 的对象都是共用该线程池,也就是说,所有使用 AsyncTask 默认生成方式,以及继承 AsyncTask 的类使用 AsyncTask 默认生成方式,他们的线程执行都是共用一个线程池,这就为什么 AsyncTask 里面使用线程池的原因。


好了,我们重新回来看看executeOnExecutor(Executor exec, Params... params)


      onPreExecute();

mWorker.mParams = params;
exec.execute(mFuture);

首先,先执行onPreExecute(),其次使用线程池调用mFuture


关于mFuture,重点为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 {
//调用postResult
postResult(result);
}
return result;
}
};

从这里可以看出,doInBackground是被线程池调用的时候执行的,也就是说,doInBackground在子线程中执行。而外,我们看看postResult(result)


    private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}

发送了一个MESSAGE_POST_RESULT消息,也就是执行刚刚我们分析过的


        case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;

至此,onPreExecutedoInBackgroundonPostExecute的一个流程我们已经分析完了,大概流程如下:


execute(AsyncTask被调用的线程)-->onPreExecute(AsyncTask被调用的线程)-->doInBackground(子线程)-->onPostExecute(UI线程)


onProgressUpdate


剩下,我们来看遗漏的onProgressUpdate


首先,onProgressUpdate要被调用的话,需要先调用publishProgress


    @WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

其实就是使用InternalHandler发送MESSAGE_POST_PROGRESS


             case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;

作者:不近视的猫
链接:https://juejin.cn/post/7109716545705771039
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册