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的工作原理基本已经分析完毕了,如果有遗漏或者错误的地方,麻烦大神指出来,相互交流,相互进步。

  • 相关阅读:
    codeforces C. Cows and Sequence 解题报告
    codeforces A. Point on Spiral 解题报告
    codeforces C. New Year Ratings Change 解题报告
    codeforces A. Fox and Box Accumulation 解题报告
    codeforces B. Multitasking 解题报告
    git命令使用
    shell简单使用
    知识束缚
    php 调用系统命令
    数据传输方式(前端与后台 ,后台与后台)
  • 原文地址:https://www.cnblogs.com/huangjialin/p/8547178.html
Copyright © 2011-2022 走看看