当前位置: 代码迷 >> 综合 >> Android 线程切换(1): AsyncTask
  详细解决方案

Android 线程切换(1): AsyncTask

热度:30   发布时间:2023-12-12 20:17:12.0

文章目录

      • 介绍
      • AsyncTask 结构
      • 并行执行任务

基于Android 9.0

介绍

AsyncTask 封装了线程池和 Handler,以用来在完成耗时操作后方便的更新 UI;
AsyncTask 是一个抽象的泛型类,它有三个泛型参数 Params, Progress, Result

  • Params:参数类型
  • Progress:后台任务的执行进度类型
  • Result:后台任务的返回结果类型

这三个类型对应了 AsyncTask 的4个重要方法:

  • onPreExecute():在主线程执行,用来在任务执行前一些初始化工作。
  • doInBackground(Params… params):在线程池中执行,用来执行任务。
  • publishProgress(Progress… values):在主线程执行,被doInBackground调用来更新任务进度。
  • onPostExecute(Result result):在主线程执行,接收doInBackground执行完成后的结果。

AsyncTask 结构

以下是 AsyncTask 的时序图。时序图
时序图中的角色分别是:

  • SERIAL_EXECUTOR:待执行任务的缓存队列。
  • THREAD_POOL_EXECUTOR:执行任务的线程池。
  • FutureTask:执行任务的封装类。
  • WorkerRunnable:具体执行任务的场景类。

从时序图可以看出,WorkerRunnable 是在线程池 THREAD_POOL_EXECUTOR 的线程执行的,因此doInBackground是在子线程中执行的,而其他几个方法都是在主线程中执行的。
而调用线程池执行所有任务的地方是在 SERIAL_EXECUTOR 中,即 SerialExecutor#execute 方法中:

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);}}
}

并行执行任务

可以看出 SerialExecutor 的执行逻辑是通过scheduleNext将 mTasks,即 AsyncTask 中的所有执行任务串行执行。而我们都知道,线程池是可以并行执行的,如果我们想使 AsyncTask 并行执行任务,只需要将任务直接放入 THREAD_POOL_EXECUTOR 中,就可以达到并行的目的(实际上 AsyncTask 的早期实现就是这样的)。具体做法我们可以通过反射调用 AsyncTask的setDefaultExecutor 方法(该方法被隐藏)将 AsyncTask.THREAD_POOL_EXECUTOR 作为参数传进去,以取代SERIAL_EXECUTOR

ReflectUtils.reflect(AsyncTask.class).method("setDefaultExecutor", 	AsyncTask.THREAD_POOL_EXECUTOR);
  相关解决方案