Android源码之路(二、AsyncTask)

参考

https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErtRW7VD-sNEgCRNespIhSK&wd=&eqid=9a27957100030dcd000000065aac77c0

https://www.jianshu.com/p/79cc3c5fc9a3

http://blog.csdn.net/majihua817/article/details/51658465

以下用法和源码分析基于android-27(即版本android 8.1.0)

要点总结:

1.进程所有AsyncTask默认并不是并行执行的,通常默认的 使用execute执行 的AsyncTask是排队按顺序执行的,同一时间内只有一个AsyncTask会运行;

2.进程中使用executeOnExecutor(Executor exec,Params...params)根据传入的线程池效果,可以实现同一时间多个AsyncTask异步执行的效果;

3.常用的回调方法有:onPreExecute()、doInBackground(Params... params)、onProgressUpdate(Progress... values)、onPostExecute(Result result)

  • a. 执行顺序为onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute

  • b. onPreExecute: 运行在ui线程,当代码执行AsyncTask.execute(Params...params)后会被调用,一般可用于界面上一些初始化操作,比如弹出下载对话框等;

  • c. doInBackground:运行在后台非ui线程,用来处理耗时的任务,如下载、数据处理等;

  • d. onProgressUpdate:运行在ui线程,可用来处理界面上的一些进度更新相关操作;在doInBackground中调用publishProgress后,可触发onProgressUpdate;

  • e. 当然onPreExecute也可以使用publishProgress触发onProgressUpdate,只是二者都是ui线程,所以并没有实际意义;

  • f. 注意的是publishProgress也是使用的handler发送消息来触发的onProgressUpdate,所以注意的是
    doInBackground没人为干预的话并不会因此堵塞等待onProgressUpdate执行完毕

  • g. onPostExecute:运行在ui线程,可用于界面提示操作完成,在doInBackground执行完使用return后调用;

  • h.源码中对这些重要回调方法都有对应的@MainThread、@WorkerThread线程注解,但这个注解目前主要用于IDE编译检查错误用的,实际上execute等依旧可以在子线程中调用,当然onPreExecute此时就不能处理ui界面,否则会抛出异常;但建议调用的地方和注解一致

4.执行过一个次或者正在执行的AsyncTask不能再次通过execute或者executeOnExecutor进行重复执行

5.使用executeOnExecutor并行执行的话,根据传入的线程池的设置会有队列大小的限制,通常直接使用AsyncTask中AsyncTask.THREAD_POOL_EXECUTOR这个线程池的话:

//cpu核数,假设4
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 
//核心线程数,3
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大同时执行的线程数9   
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空闲线程超过30秒被回收
private static final int KEEP_ALIVE_SECONDS = 30;               
//等待队列允许的最大数量为128
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
        sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;

(假设终端cpu数目为4)因为该线程池运行同时运行的最大线程数为9,等待队列最大为128,如果每一个asynctask的doInBackground中耗时非常久,一次性添加超过9+128=137个task的话(比如listview中一次性创建),那么将会引起异常java.util.concurrent.RejectedExecutionException

6.使用execute的话,因为有队列缓存(没大小限制,除非内存爆掉),串行执行,所以不存在线程池中任务超出大小的情况

7.AsyncTaskd的cancel方法只是简单把标志位改为true,最后使用Thread.interrupt去中断线程执行,但是这并不保证会马上停止执行,所以可以在doInBackground中使用isCancelled来判断任务是否被取消

要点解释

(来自参考资料https://www.jianshu.com/p/79cc3c5fc9a3)

在Android 1.5刚引入的时候,AsyncTask的execute是串行执行的;到了Android 1.6直到Android 2.3.2,又被修改为并行执行了,这个执行任务的线程池就是THREAD_POOL_EXECUTOR,因此在一个进程内,所有的AsyncTask都是并行执行的;但是在Android 3.0以后,如果你使用execute函数直接执行AsyncTask,那么这些任务是串行执行的。因此结论就来了:Android 3.0以上,AsyncTask默认并不是并行执行的。

由于同一个进程的AsyncTask都是在一个线程池中,如果默认是并行的,那么多个线程同时执行多个task中的doInBackground操作,而doInBackground又访问修改相同的资源,这边往往会忽略对资源的同步处理问题,经常会导致不可预料的错误结果,为此默认情况下使用execute执行的AsyncTask默认为串行执行;

如果处理好资源同步问题,可以使用executeOnExecutor传入合适的线程池,来达到AsyncTask并行执行的效果;

优缺点总结

优点:

  • 1.封装后实现简单的的子线程和ui线程间的一个切换,省去了用户需要子线程更新ui界面繁琐的操作

缺点(参考http://blog.csdn.net/goodlixueyong/article/details/45895997):

  • 1.需要注意串行还是并行执行,在1.5是串行,1.6-2.3.2是并行,3.0之后默认使用execute时串行,如果使用executeOnExecutor则是并行;

  • 2.所谓的串行,实际上主要是针对doInBackground方法里面的操作而言的,串行时并不会等到task中onPostExecute执行完才触发下一份asynctask,只要doInBackground执行完成就会促发下一个asynctask

  • 3.可能导致内存泄露或者ui更新异常问题,如果是activity中非静态内部asynctask子类,默认隐式持有一个activity的引用,在activity销毁之前,注意要停止asynctask;不然后台线程一直运行,导致了内存泄露,还可能在要更新ui时,该view已经不存在而导致异常;

  • 4.如果activity因为转屏重建或者被后台异常终结,之前运行的asynctask还会持有一个之前activity的引用,更新这个无效的引用上的view需要注意对view有效性的判断

  • 5.并行执行的时候,需要考虑下线程池能够处理的任务大小

使用方法

声明MyAsyncTask继承并实现AsyncTask相关回调:

    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
        String TAG="MyAsyncTask";
        public MyAsyncTask(String tag) {
            super();
            this.TAG=tag;
        }
        //doInBackground开始之前调用,ui线程,可用于界面上的一些初始化操作,比如弹出下载对话框
        @Override
        protected void onPreExecute() {
            Log.d(TAG,"onPreExecute "+Thread.currentThread());
            Toast.makeText(context,"onPreExecute",Toast.LENGTH_SHORT).show();
        }
        //用于执行后台任务,非ui线程,用于处理耗时任务,下载,数据处理等
        @Override
        protected Boolean doInBackground(String... params) {
            Log.d(TAG,"doInBackground "+Thread.currentThread());
            int count = params.length;
            for(int i=0;i<count;i++){
            //判断任务是否取消,取消则停止,用户调用AsyncTask.cancel()后设置该标志位
            //调用AsyncTask.cancel()并不能直接停止一个asynctask,
           // 需要在doInBackground/onProgressUpdate/onPreExecute手动判断该标志位
                if(isCancelled()){
                    return false
                }
                String p = params[i];
                Log.d(TAG,"doInBackground:"+p);
                publishProgress(i);
            }
            return true;
        }

        //当后台任务doInBackground调用了publishProgress(Progress...)方法后,这个方法会被调用
        //用于执行处理过程中的进度更新之类,ui线程,可用于更新下载对话框的进度条
        @Override
        protected void onProgressUpdate(Integer... values) {
            Log.d(TAG,"onProgressUpdate:"+values[0]+"  "+Thread.currentThread());
            Toast.makeText(context,"onProgressUpdate:"+values[0],Toast.LENGTH_SHORT).show();
        }

        //当后台任务doInBackground执行完毕并通过return语句进行返回时,这个方法就会被调用
        //ui线程,可用于界面更新处理完成
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            Log.d(TAG,"onPostExecute:"+aBoolean+"  "+Thread.currentThread());
            Toast.makeText(context,"onPostExecute",Toast.LENGTH_SHORT).show();
        }


        //AsyncTaskd的cancel方法只是简单把标志位改为true,最后使用Thread.interrupt去中断线程执行,但是这并不保证会马上停止执行,所以可以在doInBackground中使用isCancelled来判断任务是否被取消
        //ui线程,可用于取消后关闭ui界面提示等
        @Override
        protected void onCancelled(Boolean aBoolean) {
            Log.d(TAG,"onCancelled:"+aBoolean+"  "+Thread.currentThread());
        }

    }

创建相关实例并执行AsyncTask:

测试一:普通使用

    Log.d(TAG,"btn1 start");
     MyAsyncTask myAsyncTask =new MyAsyncTask("task1"); //创建AsyncTask子类实例
     myAsyncTask.execute("参数1","参数2");      //开始执行
     Log.d(TAG,"btn1 end");
    
    **日志输出**:
    btn1 start                              
    onPreExecute Thread[main,5,main]      //可以看见调用execute后,onPreExecute立马执行
    btn1 end
    doInBackground Thread[AsyncTask #1,5,main]   
    doInBackground:参数1
    doInBackground:参数2
    //doInBackground调用publishProgress后,由handler触发onProgressUpdate,与doInBackground为2个线程异步执行
    onProgressUpdate:0  Thread[main,5,main]  
    onProgressUpdate:1  Thread[main,5,main]
    onPostExecute:true  Thread[main,5,main] //全部操作完成后调用

测试二:多个asyncTask使用验证串行执行

    Log.d(TAG,"btn1 start");
    MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.execute("参数1","参数2");
    myAsyncTask2.execute("参数1","参数2");
    Log.d(TAG,"btn1 end");
                    
    日志输出:
    btn1 start
    //可以看见各自调用execute后,task1,task2的onPreExecute立马执行,互不影响
    task1: onPreExecute Thread[main,5,main] 
    task2: onPreExecute Thread[main,5,main]
    btn1 end
    task1: doInBackground Thread[AsyncTask #1,5,main] //doInBackground是按序执行的
    task1: doInBackground:参数1
    task1: doInBackground:参数2
    task2: doInBackground Thread[AsyncTask #2,5,main]
    task2: doInBackground:参数1
    task2: doInBackground:参数2
    //onProgressUpdate和onProgressUpdate也是按序执行的
    //这边看到可能存在后续asyncTask执行doInBackground过程中,
    前面的task才刚触发onProgressUpdate和onPostExecute
    task1: onProgressUpdate:0  Thread[main,5,main]   
    task1: onProgressUpdate:1  Thread[main,5,main]  
    task1: onPostExecute:true  Thread[main,5,main]
    task2: onProgressUpdate:0  Thread[main,5,main]
    task2: onProgressUpdate:1  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]

测试三:并行执行:

MyAsyncTask myAsyncTask =new MyAsyncTask("task1");
    MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");
    myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"参数1","参数2");
    myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"参数1","参数2");
    日志输出(doInBackground 添加Thread.sleep方便模拟):
    btn1 start
    task1: onPreExecute Thread[main,5,main]
    task2: onPreExecute Thread[main,5,main]
    //task1与task2的doInBackground部分交替执行
    task1: doInBackground Thread[AsyncTask #1,5,main]
    task1: doInBackground:参数1                             
    task2: doInBackground Thread[AsyncTask #2,5,main]
    task2: doInBackground:参数1                             
    btn1 end
    task1: onProgressUpdate:0  Thread[main,5,main]
    task2: onProgressUpdate:0  Thread[main,5,main]
    task1: doInBackground:参数2
    task2: doInBackground:参数2
    task1: onProgressUpdate:1  Thread[main,5,main]
    task2: onProgressUpdate:1  Thread[main,5,main]
    task1: onPostExecute:true  Thread[main,5,main]
    task2: onPostExecute:true  Thread[main,5,main]

从测试中可以看出onPreExecute在各自AsyncTask调用execute后立即执行,后续源码分析可知道onPreExecute不由handler触发,否则可能与doInBackground执行时序有差别;

测试二中:
后续从源码分析可以知道使用execute触发的AsyncTask中的doInBackground部分实际上是在线程池中排队执行的,所以只有一个任务的doInBackground执行完,才会获取下一个任务的doInBackground进行执行;

从源码分析可以知道onProgressUpdate、onPostExecute是通过handler消息控制的,本身也是按序执行的;多个AsyncTask的不同的生命周期步骤其实会有穿插;

从日志输出和源码原理可知,AsyncTask的按序执行相对来讲有一定的不足,不会等待一个AsyncTask完整执行完后onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute,后下一个AsyncTask才允许开始它的生命周期;

测试三中:
验证了执行线程池并行执行的效果


源码分析

AsyncTask开始执行工作的入口函数为AsyncTask.execute,所以从该方法入手查看

AsyncTask源码

execute函数

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

注解上也表明该方法运行需要在ui线程运行,为什么需要呢?此为问题一;

这边使用execute触发会使用默认的线程池SerialExecutor sDefaultExecutor,
该线程池实际上只起到一个队列控制,保存task依次按顺序执行;
假设需要并发执行AsyncTask,则可以直接使用executeOnExecutor方法
传入合适的线程池就可以达到效果;

接着查看调用的executeOnExecutor所执行的操作
executeOnExecutor函数
@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;
}
  • 首先该方法会进行一个AsyncTask状态的判断,如果该AsyncTask已经运行过或者正在运行则抛出异常,
    每个AsyncTask只允许直接或者间接调用一次executeOnExecutor;

  • 状态判断AsyncTask尚处于等待状态Status.PENDING,则将该状态标识为Status.RUNNING正在运行状态等待后续线程池排队执行;

  • 注意,接着立即执行onPreExecute()方法,也就是用于初始化ui控件准备工作的方法;
    这边说明了前面2个问题:

    • 1、onPreExecute()方法在execute()方法调用后会立即执行;
    • 2、execute()假设在非ui线程调用,则onPreExecute()也在非ui线程执行,将导致抛出更新ui异常,此为上述问题一,需要要求execute或或者executeOnExecutor在ui线程执行;
    • 3、虽然注解和源码注释要求要在ui线程执行execute()或者executeOnExecutor,但假设你没有重写onPreExecute()进行ui操作(默认是空操作),是可以在子线程中执行的(可能IDE会有提示错误,但运行的时候没出现异常),当然强烈建议执行线程和注解一致
    mWorker.mParams = params;
    exec.execute(mFuture);

然后将传入的params参数赋值给mWorker.mParams(params后续会传递给doInBackground进行处理),调用线程池exec处理mFuture;

这边需要对mWorker、mFuture和线程池exec进行分析,首先对于exec可以看出传入的是线程池SerialExecutor

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

对于线程池SerialExecutor

  • 通过上述分析知道SERIAL_EXECUTOR的定义是静态的,也就是类共享的,同一进程共用一个线程池,
  • 下面分析会知道SERIAL_EXECUTOR主要用来维护asynctask任务队列,按先进先出的原则顺序取出任务交给实际执行的线程池THREAD_POOL_EXECUTOR进行执行
  • 对于THREAD_POOL_EXECUTOR也是静态的,并且执行完一个后才会处理下一个任务;
  • 因此如果同时创建多个AsyncTask后使用execute进行执行,默认是加入到SERIAL_EXECUTOR进行排队等待执行的,一个时刻只有一个AsyncTask在执行;
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;

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

//实际执行任务的线程池,注意是静态的,所以AsyncTask共用
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;
}
    
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();        //即调用 FutureTask mFuture.run()方法    
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
            //THREAD_POOL_EXECUTOR为实际执行任务的线程池
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

可以看出该SerialExecutor在被调用execute后,会将一个任务添加到队列ArrayDeque中(即前面exec.execute(mFuture)),execute传入的是实现了Runnable接口的类FutureTask的实例mFuture,SerialExecutor的主要作用实际上时维护任务的队列,按顺序取出任务交给实际执行任务的线程池THREAD_POOL_EXECUTOR

第一个执行时mActive == null所以会调用scheduleNext,(按先进先出)从队列中拿出一个任务交给线程池THREAD_POOL_EXECUTOR进行执行:

  public void run() {
        try {
            r.run();        //即调用 FutureTask mFuture.run()方法    
        } finally {
            scheduleNext(); //执行完毕后,获取下一个任务进行处理
        }
    }

执行的即为传入的mFuture.run()方法,执行完成后会再次调用scheduleNext获取并执行下一个AsyncTask任务。
下面看一下FutureTask.run()方法所做的操作

FutureTask类

//FutureTask类构造函数,这边传入的实际上是实现了Callable接口的WorkerRunnable类对象mWorker
//mWorker与mFuture的关联在AsyncTask创建时构造函数中完成
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

//线程池THREAD_POOL_EXECUTOR中执行的方法
public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;       
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();   //调用的是mWorker的call方法
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

由上述可知,线程池THREAD_POOL_EXECUTOR中执行的mFuture.run()方法中实际上会调用result = c.call()即实现了Callable接口的类的WorkerRunnable对象mWorker.call();

其中WorkerRunnable类对象mWorker、FutureTask类对象mFuture的创建和关联位于AsyncTask构造函数中;

AsyncTask构造函数

    //部分需要联系使用的成员变量
    //注意是静态的,类共享一个线程池
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //注意是静态的变量,类共享一个handler
    private static InternalHandler sHandler;                        

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    private final Handler mHandler;
    
    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        this((Looper) null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    public AsyncTask(@Nullable Handler handler) {
        this(handler != null ? handler.getLooper() : null);
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     *
     * @hide
     */
    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); //线程池中最终执行doInBackground
                    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);
                }
            }
        };
    }

由上可以看出默认构造函数会执行

public AsyncTask(@Nullable Looper callbackLooper),传入参数为null,
此时mHandler = getMainHandler()获取到一个主线程的handler;
创建了mWorker和mFuture对象,并通过mFuture = new FutureTask<Result>(mWorker)
完成mFuture与mWorker的一个关联;

后续,线程池THREAD_POOL_EXECUTOR中执行的mFuture.run()会执行到mWorker.call()由上可看出:

    try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            result = doInBackground(mParams); //线程池中最终执行doInBackground
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            postResult(result);
        }

触发执行了doInBackground(mParams)后,通过postResult(result)将结果result通过hander发出最终在handler的ui线程中触发了onPostExecute回调;

postResult函数

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
使用handler发送处理结束的消息

getMainHandler函数

private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler(Looper.getMainLooper());
        }
        return sHandler;
    }
}  

该方法简单的创建一个handler通过Looper.getMainLooper()使得该handler运行于ui线程,注意的是sHandler是静态的,也就是说进程所有的AsyncTask共享一个handler进行处理消息;

InternalHandler类和finish方法

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) {
            //接收消息并且在ui线程回调执行finish最终调用onPostExecute方法
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
            //接收消息并且在ui线程回调执行onProgressUpdate方法
                case MESSAGE_POST_PROGRESS:    
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
  • 该handler主要用于接收消息MESSAGE_POST_PROGRESS后在ui线程执行onProgressUpdate方法,
    或者接收MESSAGE_POST_RESULT后,最终在ui线程执行onPostExecute/onCancelled方法,

  • AsyncTask中2个重要的方法onProgressUpdate、onPostExecute由该handler执行;

    private void finish(Result result) {
        if (isCancelled()) {
      //任务执行完之后,如果用户之前调用了AsyncTask.cancle()则触发onCancelled
            onCancelled(result);
        } else {
      //否则触发onPostExecute
            onPostExecute(result);  
        }
        mStatus = Status.FINISHED;
    }

源码总结

  • 1.AsyncTask中存在静态的2个线程池SerialExecutor、ThreadPoolExecutor,以及一个静态的ui线程的handler
SerialExecutor implements Executor :    sDefaultExecutor
ThreadPoolExecutor :                    THREAD_POOL_EXECUTOR:
进程中对于使用execute开始的所有的AsyncTask顺序排队执行
  • 2.AsyncTask构造函数中,初始化了handler,WorkerRunnable mWorker,FutureTask mFuture,并且将mWorker关联到mFuture:
  mWorker = new WorkerRunnable<Params, Result>(){..}..
  mFuture = new FutureTask<Result>(mWorker) {..}..
  • 3.使用execute的时候:

    • 会调用executeOnExecutor()并传递SerialExecutor
    • 在executeOnExecutor()中执行onPreExecute,并将mFuture传递给SerialExecutor进行排队
    • SerialExecutor按先进先出的顺序依次取出任务给ThreadPoolExecutor进行处理,处理调用的是mFuture.run()方法实际上会执行到mWorker.call()里面的doInBackground方法,执行完成后通过handler触发onPostExecute方法;
  • 过程中如果调用publishProgress会通过handler触发onProgressUpdate;

  • 如果要并行执行asynctask则不使用execute而是直接使用executeOnExecutor传递给合适的线程池,跳过SerialExecutor的排队步骤;

扫描关注微信公众号:


qrcode_for_gh_1bbc19ef669d_258.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容