学习笔记

AsyncTask源码分析
Publish: 2018/7/23   

AsyncTask源码分析

使用规则

用法


 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

  new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask的泛型类型

  1. Params,执行时发送给任务的参数类型。
  2. Progress,后台计算期间发布的进度单元的类型。
  3. Result,背景计算结果的类型。
  4. 要将类型标记为未使用,只需使用以下类型Void:
    private class MyTask extends AsyncTask<Void, Void, Void> { ... }
    

4个重要方法

  1. onPreExecute(),在执行任务之前在UI线程上调用。此步骤通常用于设置任务,例如通过在用户界面中显示进度条。
  2. doInBackground(Params…),在onPreExecute()完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数将传递给此步骤。计算结果必须由此步骤返回,并将传递回最后一步。此步骤还可用于publishProgress(Progress…)发布一个或多个进度单位。这些值在onProgressUpdate(Progress…)步骤中发布在UI线程上 。
  3. onProgressUpdate(Progress…),在调用后在UI线程上调用publishProgress(Progress…)。执行的时间是不确定的。此方法用于在后台计算仍在执行时显示用户界面中的任何形式的进度。例如,它可用于为进度条设置动画或在文本字段中显示日志。
  4. onPostExecute(Result),在后台计算完成后在UI线程上调用。背景计算的结果作为参数传递给该步骤。

取消任务

可以随时通过调用取消任务cancel(boolean)。调用此方法将导致后续调用isCancelled()返回true。在调用此方法之后onCancelled(Object),而不是 onPostExecute(Object)在doInBackground(Object[]) 返回后调用。为确保尽快取消任务,应始终检查isCancelled()周期性 的返回值(doInBackground(Object[])如果可能)(例如在循环内)。

线程规则

此类必须遵循一些线程规则才能正常工作:

执行顺序

首次引入时,AsyncTasks在单个后台线程上串行执行。从开始Build.VERSION_CODES.DONUT(Android 1.6),这被改为一个线程池,允许多个任务并行运行。从开始 Build.VERSION_CODES.HONEYCOMB(Android 3.0),任务在单个线程上执行,以避免由并行执行引起的常见应用程序错误。

如果您真的想要并行执行,可以 executeOnExecutor(java.util.concurrent.Executor, Object[])使用 THREAD_POOL_EXECUTOR。

源码分析

静态初始化的类

创建一个核心线程数为2~4,最大线程数为CPU个数*2+1,存活时间为30秒,容量为128的LinkedBlockingQueue(更高的吞吐量,较低的可预测性)的线程池。

 //获得Java虚拟机可用的处理器数。
 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
 // 核心线程池数为最小2、3或最大4
 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
 // 最大线程池数为 可用处理器数*2+1
 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
 private static final int KEEP_ALIVE_SECONDS = 30;
 //根据计数记录Thread
 private static final ThreadFactory sThreadFactory = new ThreadFactory() {
     private final AtomicInteger mCount = new AtomicInteger(1);

     public Thread newThread(Runnable r) {
         return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
     }
 };

 private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(128);

 /**
  * An {@link Executor} that can be used to execute tasks in parallel.
  */
 public static final Executor THREAD_POOL_EXECUTOR;

 static {
     ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
             CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
             sPoolWorkQueue, sThreadFactory);
     threadPoolExecutor.allowCoreThreadTimeOut(true);
     THREAD_POOL_EXECUTOR = threadPoolExecutor;
 }

new DownloadFilesTask()

  1. mHandler 返回进度或结果
  2. mWorker 执行异步任务
  3. mFuture 结果返回主线程


 private static InternalHandler sHandler;

 private final WorkerRunnable mWorker;
 private final FutureTask mFuture;

 // 构造函数必须在UI线程调用
 public AsyncTask() {
     this((Looper) null);
 }

 public AsyncTask(@Nullable Looper callbackLooper) {
     mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

     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
                 result = doInBackground(mParams);
                 Binder.flushPendingCommands();
             } catch (Throwable tr) {
                 mCancelled.set(true);
                 throw tr;
             } finally {
                 postResult(result);
             }
             return result;
         }
     };

     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 occurred while executing doInBackground()",
                         e.getCause());
             } catch (CancellationException e) {
                 postResultIfNotInvoked(null);
             }
         }
     };
 }


通过ArrayDeque(线程不安全,当用作堆栈时,此类可能比Stack快,并且在用作队列时比LinkedList更快)缓存任务,如果执行任务失败调用scheduleNext();执行下一个任务,如果下一个任务为空,继续执行下一个任务


 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
 public static final Executor SERIAL_EXECUTOR = new 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);
         }
     }
 }

getMainHandler() 创建主线程handler

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

execute(Params… params)


exec.execute(mFuture);

-> postResultIfNotInvoked(get());

-> 调用 publishProgress(Progress… values);进度发送到mHandler
-> onProgressUpdate(Progress… values);

-> postResult(result);结果发送到mHandler

-> finish(Result result);

-> onPostExecute(result);


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

 @MainThread
 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();

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

     return this;
 }

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



← Java容器类 国际化适配笔记 →

Powered by Hexo, Theme designs by @hpcslag.
Style-Framework Tocas-UI designs by @yamioldmel