Android异步处理类AsyncTask

作者: Jesse_zhao | 来源:发表于2016-06-22 21:47 被阅读190次

    但凡接触过Android开发的人都知道UI线程是不能进行耗时操作的,否则有可能出现ANR。那么为了避免这个问题Android提供了AsyncTask来处理耗时任务如网络请求,数据库的读取等。那么接下来让我们看看AsyncTask是怎么实现的吧。

    首先来看看AsyncTask的使用:
    public classMainActivity extends AppCompatActivity {
    public static finalStringTAG="MainActivity";
    @Override
    protected voidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //任务串行执行
    new MyTask().execute("");
    //任务并行执行
    new MyTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECU  TOR,"");
    }
      private static classMyTask extends AsyncTask {
      //在执行任务之前调用(UIThread)
    @Override
    protected voidonPreExecute() {
    super.onPreExecute();
    Log.e(TAG,"onPreExecute:"+Thread.currentThread().getName());
    }
    //在执行任务执行时调用(WorkThread)返回值传入onPostExecute
    @Override
    protected String doInBackground(String... params) {
    //耗时操作代码
    try{
    for(inti =0;i <5;i++) {
    Thread.sleep(1000);
    onProgressUpdate(i*20);
    }
    }catch(InterruptedException e) {
    e.printStackTrace();
    }
    Log.e(TAG,"doInBackground:"+Thread.currentThread().getName() );
    return null;
    }
    //在执行任务执行百分比(WorkThread)
    @Override
    protected voidonProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    Log.e(TAG,"onProgressUpdate:"+Thread.currentThread().getName() );
    }
    //在执行任务执行完成调用(UIThread)
    @Override
    protected voidonPostExecute(String s) {
    super.onPostExecute(s);
    Log.e(TAG,"onPostExecute:"+Thread.currentThread().getName());
    }
    }
    }
    
    源码分析

    AsyncTask如何工作?

    首先来看execute()和executeOnExecutor()方法:
    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {    
    return executeOnExecutor(sDefaultExecutor, params);}
    

    在这方法中会执行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;
     }
    

    从中可看出先执行的是onPreExecute()--> exec.execute(mFuture);
    exec就是execute方法传入的也就是sDefaultExecutor这个线程池,那我们再来看看这个线程池的定义及实现:

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    /*** An {@link Executor} that executes tasks one at a time in serial * order.  This serialization is global to a particular process.*/
    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);   
     }   
     }
    }
    

    这个线程池也就是串行器的实现,我们来分析下它的实现:
    首先是

    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();

    这是一个线性的双向队列,用于存储AsyncTask任务,当有新的任务时就是调用mTasks.offer()(此方法将指定的元素,在此deque队列的末尾);然后执行scheduleNext();在这方法中会执行队列中排列最前的任务THREAD_POOL_EXECUTOR.execute(mActive);
    下面是THREAD_POOL_EXECUTOR的定义:

    /** * An {@link Executor} that can be used to execute tasks in parallel. */
    public static final Executor THREAD_POOL_EXECUTOR  = new   ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    

    可以看出线程池核心容量的容量是cpu核心数 +1;线程池最大容量为cpu核心数* 2 + 1;过剩的空闲线程的存活时间为1秒;待执行的任务队列初始容量:128个 。
    通过上面的分析可以知道,不管是串行执行任务还是并行执行,其中的区别就是传入给executeOnExecutor()的线程池的不同,串行就是sDefaultExecutor,当然也可以指定自己定义的串行器,而并行则可以自己指定线程池来执行。

    分析完任务的串行和并行的执行之后,接下来来看看doInBackground()是何时开始执行以及是如何将执行结果返回给onPostExecute()的:首先在AsyncTask的构造方法中定义了个WorkerRunnable<Params, Result> implements Callable<Result>和一个FutureTask,不了解Callable和Future的可以看这里,我们看下构造方法中WorkerRunnable的实现
    mWorker = new WorkerRunnable<Params, Result>() {   
     public Result call() throws Exception {        
    mTaskInvoked.set(true);              
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
     //任务开始执行
     Result result = doInBackground(mParams);  
     Binder.flushPendingCommands();        
    return postResult(result);  
      }};
    

    通过上面代码可以发现执行后将结果交给postResult(result)方法处理,那我们在来看看这个方法的实现:

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

    看到这个方法后就明白了,AsyncTask的原理就是封装了handler+Thread。

    总结:

    AsyncTask内部封装了Thread和Handler,调用AsyncTask的executeOnExecutor方法可以实现任务的并行执行也可以自定义线程池,调用execute方法可以实现任务的串行执行。

    相关文章

      网友评论

        本文标题:Android异步处理类AsyncTask

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