美文网首页
AsyncTask源码分析

AsyncTask源码分析

作者: 萍水相逢_程序员 | 来源:发表于2018-09-01 11:32 被阅读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模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。

    相关文章

      网友评论

          本文标题:AsyncTask源码分析

          本文链接:https://www.haomeiwen.com/subject/jsgywftx.html