AsyncTask源码分析

2018-09-01  本文已影响0人  萍水相逢_程序员

一 AsyncTask使用的场景

在MainThread线程中执行耗时不长的最多几秒钟的后台工作。

二 AsyncTask使用的方试

继承AsyncTasK,
重写
onPreExecute(),
doInBackground(),
onProgressUpdate(),
onPostExecute()
相应的方法,
至少需要重写doInBackground(),其它方法根据实际情况重写.源码中的注解已经直白的反映了是否可以UI刷新操作。

    @MainThread
    protected void onPreExecute() {
    }
    
    @WorkerThread
    protected abstract Result doInBackground(Params... params);
    
     @MainThread
    protected void onProgressUpdate(Progress... values) {
    }
    
    @MainThread
    protected void onPostExecute(Result result) {
    }

三 . 回调方法的执行顺序(正常流程,刨除任务的重复提交和取消任务的场景)

  1. AsyncTask构造初始化后
  2. 调用execute(Params... params)方法后,
  3. 就先调用onPreExecute,
  4. 之后线程执行会调用doInBackground(),在这个方法执行你需要产生的耗时操作,
  5. 如果想更新耗时操作的进度, 则你可以在重写doInBackground()方法中调用publishProgress(Progress... values)方法, 此方法会让onProgressUpdate()方法执行。
  6. 线程用到的是FutureTask,最后在线程执行完后回调到done(),
  7. 在此后会触发onPostExecute();

四 .对每个方法运行在WorkerThread,MainThread说明

  1. onPreExecute 运行在MainThread, 反过来要求使用AsyncTask,在执行调用execute()时必需在UI thread中;
  2. doInBackground运行在WorkerThread,是通过FutureTask封装Callable,运行在新的线程中;
  3. onProgressUpdate,onPostExecute运行在MainThread, 是通过内部封装handle message机制WorkerThread切换到MainThread,即通过这样方式InternalHandler(Looper.getMainLooper())

五 AsyncTask泛型的说明

public abstract class AsyncTask<Params, Progress, Result>

  1. 第一个泛型参数Params 对应execute(Params... params)传入的参数,并在doInBackground中使用的参数。
  2. 第二个泛型参数Progress, publishProgress(Progress... values) onProgressUpdate(Progress... values)参数
  3. 第三个泛型参数Result,对应于是doInBackground方法的返回值类型和onPostExecute(Result result)

六 AsyncTask取消任务

1 . 需要对取消任务后做相应操作,可以重写

    @MainThread
     protected void onCancelled() {}
  1. 在需要取消的地方调研cancel(true)
 public final boolean cancel(boolean mayInterruptIfRunning) {
       mCancelled.set(true);
       return mFuture.cancel(mayInterruptIfRunning);
  }
  1. mCancelled.set(true)后
  2. 调用 iscancelled()并且返回true,
  3. 在doInBackground中返回后 ,执行postResult(result);
  4. 执行postResult(result)后,通过handle机制调用到finish(Result result)
  private void finish(Result result) {
       if (isCancelled()) {
             onCancelled(result);
        } else {
              onPostExecute(result);
        }
        mStatus = Status.FINISHED;
   }

通过finish的判断逻辑可知道不会执行onPostExecute(result),执行onCancelled(result);之后执行onCancelled();

通过取消流程, 如果有取消任务的场景,一般在实现doInBackground和onProgressUpdate做好判断.

七 AsyncTask使用规则

  1. The AsyncTask class must be loaded on the UI thread;
  2. The task instance must be created on the UI thread;
  3. execute() must be invoked on the UI thread;
  4. Do not call onPreExecute(), onPostExecute(),doInBackground(),onProgressUpdate();
  5. he task can be executed only once (an exception will be thrown if a second execution is attempted.)

八 线程池使用的变迁

When first introduced, AsyncTasks were executed serially on a single background thread。

Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed to a pool of threads allowing multiple tasks to operate in parallel。

Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

目前源码中使用的默认线程池


 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);
            }
        }
    }
1 SerialExecutor通过ArrayDeque队列来管理Runnable对象
  1. 第一调用execute时,会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部, 然后判断mActive对象是不是等于null,

  2. 第一次运行当然是等于null了,于是会调用scheduleNext()方法。在这个方法中会从队列的头部取值,并赋值给mActive对象,

  3. 然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,

  4. 但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,于是就不会再调用scheduleNext()方法。

2 offer()方法里传入的Runnable匿名类

这里使用了一个try finally代码块,并在finally中调用了scheduleNext()方法,保证无论发生什么情况,这个方法都会被调用。也就是说,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。

上一篇下一篇

猜你喜欢

热点阅读