Android AsyncTask内部原理
yaya8_27@
8年前
<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>