zoukankan      html  css  js  c++  java
  • AsyncTask的工作原理

    AsyncTask是Android本身提供的一种轻量级的异步任务类。它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI。实际上,AsyncTask内部是封装了Thread和Handler。虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池。好了,话不多说了,我们先看看AsyncTask的简单用法吧。

    AsyncTask是一个抽象的泛型类。简单的介绍一下它的使用方式代码如下:

     1  
     2 
     3 package com.example.huangjialin.myapplication;
     4 
     5  
     6 import android.os.AsyncTask;
     7 
     8 import android.util.Log;
     9 
    10  
    11 /**
    12 
    13  * Created by huangjialin on 2018/3/11.
    14 
    15  */
    16 
    17 public class AsyncTaskTest extends AsyncTask<String, Object, Long>{
    18 
    19  
    20     @Override
    21 
    22     protected void onPreExecute() {
    23 
    24         super.onPreExecute();
    25 
    26         Log.i("AsyncTaskTest","---准备下载---");
    27 
    28     }
    29 
    30  
    31 
    32     @Override
    33 
    34     protected Long doInBackground(String... params) {
    35 
    36  
    37 
    38         Log.i("AsyncTaskTest","---在后台正在下载---");
    39 
    40         return null;
    41 
    42     }
    43 
    44 
    45     @Override
    46 
    47     protected void onProgressUpdate(Object... values) {
    48 
    49         super.onProgressUpdate(values);
    50 
    51         Log.i("AsyncTaskTest","---在更新---");
    52 
    53     }
    54 
    55  
    56 
    57     @Override
    58 
    59     protected void onPostExecute(Long aLong) {
    60 
    61         super.onPostExecute(aLong);
    62 
    63         Log.i("AsyncTaskTest","---下载完成,将结果返回到主线程--");
    64 
    65     }
    66 
    67 }

    然后在activity中调用 new AsyncTaskTest().execute();就可以了...使用起来比较简单,这里就不在讲述怎么使用了。

    AsyncTask提供有4个核心方法:

    1、onPreExecute():该方法在主线程中执行,在执行异步任务之前会被调用,一般用于一些准备工作。

    2、doInBackground(String... params):这个方法是在线程池中执行,此方法用于执行异步任务。在这个方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法,另外,任务的结果返回给onPostExecute方法。

    3、onProgressUpdate(Object... values):该方法在主线程中执行,主要用于任务进度更新的时候,该方法会被调用。

    4、onPostExecute(Long aLong):在主线程中执行,在异步任务执行完毕之后,该方法会被调用,该方法的参数及为后台的返回结果。

    除了这几个方法之外还有一些不太常用的方法,如onCancelled(),在异步任务取消的情况下,该方法会被调用。

    好了,AsyncTask基本的使用就介绍到这里,下面我们进入主题,我们一起看看AsyncTask的工作原理。

    AsyncTask的工作原理

    先从execute走起,源码来了

       

     1  @MainThread
     2 
     3     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
     4 
     5         return executeOnExecutor(sDefaultExecutor, params);
     6 
     7     }
     8 
     9  
    10 
    11     @MainThread
    12 
    13     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
    14 
    15             Params... params) {
    16 
    17         if (mStatus != Status.PENDING) {
    18 
    19             switch (mStatus) {
    20 
    21                 case RUNNING:
    22 
    23                     throw new IllegalStateException("Cannot execute task:"
    24 
    25                             + " the task is already running.");
    26 
    27                 case FINISHED:
    28 
    29                     throw new IllegalStateException("Cannot execute task:"
    30 
    31                             + " the task has already been executed "
    32 
    33                             + "(a task can be executed only once)");
    34 
    35             }
    36 
    37         }
    38 
    39  
    40         mStatus = Status.RUNNING;
    41 
    42  
    43 
    44         onPreExecute();
    45 
    46  
    47 
    48         mWorker.mParams = params;
    49 
    50         exec.execute(mFuture);
    51 
    52  
    53 
    54         return this;
    55 
    56     }

    为了方面分析,我就把英文注释干掉了…源码可以知道从上面的execute方法内部调用的是executeOnExecutor()方法。而sDefaultExecutor实际上是一个串行的线程池。而onPreExecute()方法在这里就会被调用了。接着看这个线程池。

      1  private static class SerialExecutor implements Executor {
      2 
      3         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
      4 
      5         Runnable mActive;
      6 
      7  
      8         public synchronized void execute(final Runnable r) {
      9 
     10             mTasks.offer(new Runnable() {
     11 
     12                 public void run() {
     13 
     14                     try {
     15 
     16                         r.run();
     17 
     18                     } finally {
     19 
     20                         scheduleNext();
     21 
     22                     }
     23 
     24                 }
     25 
     26             });
     27 
     28             if (mActive == null) {
     29 
     30                 scheduleNext();
     31 
     32             }
     33 
     34         }
     35 
     36  
     37 
     38         protected synchronized void scheduleNext() {
     39 
     40             if ((mActive = mTasks.poll()) != null) {
     41 
     42                 THREAD_POOL_EXECUTOR.execute(mActive);
     43 
     44             }
     45 
     46         }
     47 
     48     }
     49 
     50  
     51 
     52 public AsyncTask() {
     53 
     54         mWorker = new WorkerRunnable<Params, Result>() {
     55 
     56             public Result call() throws Exception {
     57 
     58                 mTaskInvoked.set(true);
     59 
     60                 Result result = null;
     61 
     62                 try {
     63 
     64                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
     65 
     66                     //noinspection unchecked
     67 
     68                     result = doInBackground(mParams);
     69 
     70                     Binder.flushPendingCommands();
     71 
     72                 } catch (Throwable tr) {
     73 
     74                     mCancelled.set(true);
     75 
     76                     throw tr;
     77 
     78                 } finally {
     79 
     80                     postResult(result);
     81 
     82                 }
     83 
     84                 return result;
     85 
     86             }
     87 
     88         };
     89 
     90  
     91 
     92         mFuture = new FutureTask<Result>(mWorker) {
     93 
     94             @Override
     95 
     96             protected void done() {
     97 
     98                 try {
     99 
    100                     postResultIfNotInvoked(get());
    101 
    102                 } catch (InterruptedException e) {
    103 
    104                     android.util.Log.w(LOG_TAG, e);
    105 
    106                 } catch (ExecutionException e) {
    107 
    108                     throw new RuntimeException("An error occurred while executing doInBackground()",
    109 
    110                             e.getCause());
    111 
    112                 } catch (CancellationException e) {
    113 
    114                     postResultIfNotInvoked(null);
    115 
    116                 }
    117 
    118             }
    119 
    120         };
    121 
    122     }
    123 
    124  

    从上面的代码可以知道,AsyncTask的执行是排队执行的,因为有关键字synchronized,而AsyncTask的Params参数就封装成为FutureTask类,FutureTask这个类是一个并发类,在这里它充当了Runnable的作用。接着FutureTask会交给SerialExecutor的execute方法去处理,而SerialExecutor的executor方法首先就会将FutureTask添加到mTasks队列中,如果这个时候没有任务,就会调用scheduleNext()方法,执行下一个任务。如果有任务的话,则执行完毕后最后在调用 scheduleNext();执行下一个任务。直到所有任务被执行完毕。而AsyncTask的构造方法中有一个call()方法,而这个方法由于会被FutureTask的run方法执行。所以最终这个call方法会在线程池中执行。而doInBackground这个方法就是在这里被调用的。我们好好研究一下这个call()方法。

     1 public Result call() throws Exception {
     2 
     3                 mTaskInvoked.set(true);
     4 
     5                 Result result = null;
     6 
     7                 try {
     8 
     9                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    10 
    11                     //noinspection unchecked
    12 
    13                     result = doInBackground(mParams);
    14 
    15                     Binder.flushPendingCommands();
    16 
    17                 } catch (Throwable tr) {
    18 
    19                     mCancelled.set(true);
    20 
    21                     throw tr;
    22 
    23                 } finally {
    24 
    25                     postResult(result);
    26 
    27                 }
    28 
    29                 return result;
    30 
    31             }
    32 
    33         };
    34 
    35  
    36 private Result postResult(Result result) {
    37 
    38         @SuppressWarnings("unchecked")
    39 
    40         Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
    41 
    42                 new AsyncTaskResult<Result>(this, result));
    43 
    44         message.sendToTarget();
    45 
    46         return result;
    47 
    48     }

    mTaskInvoked.set(true);表示当前任务已经执行过了。接着执行doInBackground方法,最后将结果通过postResult(result);方法进行传递。postResult()方法中通过sHandler来发送消息,sHandler的代码如下:

     1 private static class InternalHandler extends Handler {
     2 
     3         public InternalHandler() {
     4 
     5             super(Looper.getMainLooper());
     6 
     7         }
     8 
     9 
    10         @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    11 
    12         @Override
    13 
    14         public void handleMessage(Message msg) {
    15 
    16             AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
    17 
    18             switch (msg.what) {
    19 
    20                 case MESSAGE_POST_RESULT:
    21 
    22                     // There is only one result
    23 
    24                     result.mTask.finish(result.mData[0]);
    25 
    26                     break;
    27 
    28                 case MESSAGE_POST_PROGRESS:
    29 
    30                     result.mTask.onProgressUpdate(result.mData);
    31 
    32                     break;
    33 
    34             }
    35 
    36         }
    37 
    38     }
    39 
    40 
    41 private void finish(Result result) {
    42 
    43         if (isCancelled()) {
    44 
    45             onCancelled(result);
    46 
    47         } else {
    48 
    49             onPostExecute(result);
    50 
    51         }
    52 
    53         mStatus = Status.FINISHED;
    54 
    55     }

    到这里,就很明了。

    注意:AsyncTask中有两个线程池,一个是SerialExecutor,另一个是THREAD_POOL_EXECUTOR,其中前者主要是任务进行排队的,后者才是真正的执行任务。

    而AsyncTask中还有一个方法InternalHandler,这个方法的主要作用是将执行环境从线程池切换到主线程的。

    到此,AsyncTask的工作原理基本已经分析完毕了,如果有遗漏或者错误的地方,麻烦大神指出来,相互交流,相互进步。

  • 相关阅读:
    本周工作量统计
    第15周个人作业
    16周第一组作业
    排球比赛积分规则
    典型用户和场景
    我和计算机
    第18周冲刺
    16周个人作业
    Java中动态获取项目根目录的绝对路径
    Spring框架下类的初始化顺序
  • 原文地址:https://www.cnblogs.com/huangjialin/p/8547178.html
Copyright © 2011-2022 走看看