Android AsyncTask内部原理

yaya8_27@ 7年前
   <h2>Android AsyncTask内部原理</h2>    <p>@(Android)</p>    <p>[toc]</p>    <h2>小笔记</h2>    <h2>基本使用</h2>    <pre>  <code class="language-java">/**   * 在主线程中调用,可以做一些初始化的操作,但是不要在这里做耗时操作   */  @Override  protected void onPreExecute() {      super.onPreExecute();  }    /**   * 在子线程中调用,耗时操作全部在这里完成。   * 如果需要更新进度可以调用 publishProgress(Progress... values)   */  @Override  protected Object doInBackground(Object[] params) {      return null;  }    /**    * 在主线程中调用,显示子线程进度的回调函数    * @param values    */   @Override   protected void onProgressUpdate(Object[] values) {       super.onProgressUpdate(values);   }    /**    * 在主线程中调用,传入的传输是在doInBackground中返回的值    * @param o    */   @Override   protected void onPostExecute(Object o) {       super.onPostExecute(o);  }    /**   * AsyncTask被取消的时候会回调   * 参数是从哪里传过来的呢。后面有解释   */  @Override  protected void onCancelled(Object o) {      super.onCancelled(o);      System.out.println(o instanceof Bitmap);      if (o instanceof Bitmap) {          image_view.setImageBitmap((Bitmap) o);      }  }  /**   * AsyncTask被取消的时候会回调   */  @Override  protected void onCancelled() {      super.onCancelled();      System.out.println("MyAsyncTask ========== onCancelled");  }</code></pre>    <p>了解了基本的使用方法之后,简单的实现一个加载图片的方法吧</p>    <pre>  <code class="language-java">package com.example.wen.asynctask;    import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.os.AsyncTask;  import android.os.Bundle;  import android.support.v7.app.AppCompatActivity;  import android.widget.ImageView;    import java.io.IOException;  import java.net.HttpURLConnection;  import java.net.MalformedURLException;  import java.net.URL;    public class MainActivity extends AppCompatActivity {        private ImageView image_view;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          image_view = (ImageView) findViewById(R.id.image_view);          new MyAsyncTask().execute();      }        class MyAsyncTask extends AsyncTask {            /**           * 在主线程中调用,可以做一些初始化的操作,但是不要在这里做耗时操作           */          @Override          protected void onPreExecute() {              super.onPreExecute();          }            /**           * 在子线程中调用,耗时操作全部在这里完成。           * 如果需要更新进度可以调用 publishProgress(Progress... values)           */          @Override          protected Object doInBackground(Object[] params) {                Bitmap bitmap = null;                try {                  URL url = new URL("https://www.baidu.com/img/bd_logo1.png");                  HttpURLConnection connection = (HttpURLConnection) url.openConnection();                    bitmap = BitmapFactory.decodeStream(connection.getInputStream());                } catch (MalformedURLException e) {                  e.printStackTrace();              } catch (IOException e) {                  e.printStackTrace();              }                return bitmap;          }            /**           * 在主线程中调用,传入的传输是在doInBackground中返回的值           * @param o           */          @Override          protected void onPostExecute(Object o) {              super.onPostExecute(o);                if (o instanceof Bitmap) {                  image_view.setImageBitmap((Bitmap) o);              }          }            /**           * 在主线程中调用,显示子线程进度的回调函数           * @param values           */          @Override          protected void onProgressUpdate(Object[] values) {              super.onProgressUpdate(values);          }            /**           * AsyncTask被取消的时候会回调           */          @Override          protected void onCancelled(Object o) {              super.onCancelled(o);              System.out.println(o instanceof Bitmap);              if (o instanceof Bitmap) {                  image_view.setImageBitmap((Bitmap) o);              }          }          /**           * AsyncTask被取消的时候会回调           */          @Override          protected void onCancelled() {              super.onCancelled();              System.out.println("MyAsyncTask ========== onCancelled");          }      }  }</code></pre>    <h2>内部实现原理</h2>    <ol>     <li>在主线程中调用 execute(Params... params) 方法或者是指定的线程池的 executeOnExecutor(Executor exec,Params... params)</li>    </ol>    <pre>  <code class="language-java">@MainThread  public final AsyncTask<Params, Progress, Result> execute(Params... params) {      return executeOnExecutor(sDefaultExecutor, params);  }    @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;  }</code></pre>    <p>从上面的代码中看到两点:</p>    <ol>     <li>onPreExecute() 方法在主线程中调用的</li>     <li>另外,在执行 exec.execute(mFuture); 的时候,会先判断 mStatus 的状态。所以每一个AsyncTask对象都只能调用 execute() 方法一次。看一下mStatues的定义:</li>    </ol>    <pre>  <code class="language-java">private volatile Status mStatus = Status.PENDING;    public enum Status {      /**       * Indicates that the task has not been executed yet.       */      PENDING,      /**       * Indicates that the task is running.       */      RUNNING,      /**       * Indicates that {@link AsyncTask#onPostExecute} has finished.       */      FINISHED,【  }</code></pre>    <p>从定义中看到 mStatus 是用 volatile 关键字修饰的。 volatile 的作用是保证操作的 <strong>可见性</strong> ,即修改之后其他能马上读取修改后的值。详情看 <a href="https://app.yinxiang.com/Home.action#n=9ae62930-e92b-4198-a495-724bc94edb4c&ses=4&sh=2&sds=5&" rel="nofollow,noindex">Java 并发编程</a> 。</p>    <p>那为什么需要用一个 volatile 关键字修饰呢。现在有这么一个场景,一个 AsyncTask 对象已经快执行完后台任务了,准备修改状态 Statue.FINISH ,但是这个时候,主线程保留了这个 AsyncTask 对象,并且调用了 execute() 方法,这个时候就会导致一个 AsyncTask 被调用了两次。</p>    <p>而一个 AsyncTask 不允许执行两次的原因是考虑到了线程安全的问题,如果一个对象被执行了两次,那么就需要考虑自己定义的成员变量的线程安全的问题了。所以直接在new一个出来比执行两次的方式更加方便。</p>    <p>当判断是第一次调用的时候,后面就会调用到 exec.execute(mFuture); 方法。线程池中的 exec.execute() 需要一个 Runnable 的对象,所以让我们看看mFuture的定义吧:</p>    <pre>  <code class="language-java">private final FutureTask<Result> mFuture;</code></pre>    <p>我们发现他是一个 FutureTask 对象。 FutrueTask 对象需要实现一个方法:</p>    <pre>  <code class="language-java">/**    * Protected method invoked when this task transitions to state    * {@code isDone} (whether normally or via cancellation). The    * default implementation does nothing.  Subclasses may override    * this method to invoke completion callbacks or perform    * bookkeeping. Note that you can query status inside the    * implementation of this method to determine whether this task    * has been cancelled.    */  protected void done() { }</code></pre>    <p>并且在 FutureTask 的构造方法中,需要传一个 Callable 对象,那么 Callable 又是一个什么东西呢。简单来说, Callable 是一个有返回值的 Runnable 。所以 FutureTask 在后台运行的代码就是 Callable 中的 call() 的方法。具体来看看在 AsyncTask 源码中是怎么实现的:</p>    <pre>  <code class="language-java">mWorker = new WorkerRunnable<Params, Result>() {      public Result call() throws Exception {          mTaskInvoked.set(true);            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);          //noinspection unchecked          Result result = doInBackground(mParams);          Binder.flushPendingCommands();          return postResult(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);          }      }  };</code></pre>    <p>上面看到的 mWorker 是一个实现了 Callable 的类,并且用一个变量保存了在执行 AsyncTask 时传入的参数</p>    <pre>  <code class="language-java">private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {      Params[] mParams;  }</code></pre>    <p>上面的代码的大概意思就是在一个子线程中调用了我们实现的 doInBackground() 方法。在 FutureTask 中的 done() 方法中有一个 get() 方法,作用就是获取 doInBackground() 返回的数据。然后将返回的数据传到 postResult 方法中:</p>    <pre>  <code class="language-java">private Result postResult(Result result) {     Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,             new AsyncTaskResult<Result>(this, result));     message.sendToTarget();     return result;  }</code></pre>    <p>在这里可以看到 AsyncTask 的内部是通过 Handler 来实现的。这里还有一个 AsyncTaskResult :</p>    <pre>  <code class="language-java">private static class AsyncTaskResult<Data> {      final AsyncTask mTask;      final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {          mTask = task;          mData = data;      }  }    private void finish(Result result) {   if (isCancelled()) {          onCancelled(result);      } else {          onPostExecute(result);      }      mStatus = Status.FINISHED;  }    private static class InternalHandler extends Handler {      public InternalHandler() {          super(Looper.getMainLooper());      }        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})      @Override      public void handleMessage(Message msg) {          AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;          switch (msg.what) {              case MESSAGE_POST_RESULT:                  // There is only one result                  result.mTask.finish(result.mData[0]);                  break;              case MESSAGE_POST_PROGRESS:                  result.mTask.onProgressUpdate(result.mData);                  break;          }      }  }</code></pre>    <p>因为在 finish() 方法中需要判断Task是否被取消,而Status是对象内部的成员变量,所以需要保留一个 AsyncTask 对象和在子线程中返回的数据。</p>    <p>当执行完 finish() 方法之后,基本 AsyncTask 的内部原理都讲完了。耶!!</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/2f755d2af53d</p>    <p> </p>