AsyncTask原理分析

-----基于Android6.0分析
AsyncTask是一個(gè)抽象類,我們?nèi)ナ褂盟臅r(shí)候需要?jiǎng)?chuàng)建一個(gè)子類繼承它。
它是Android為我們封裝的處理耗時(shí)操作的類
AsyncTask也是使用的異步消息處理機(jī)制,只是做了非常好的封裝而已。

framework/base/core/java/android/os/AsyncTask.java
public abstract class AsyncTask<Params, Progress, Result>

AsyncTask的參數(shù)由三個(gè)泛型設(shè)定,所以當(dāng)我們創(chuàng)建子類的時(shí)候必須為其制定泛型的類型,下面由一個(gè)例子來(lái)說(shuō)明,這三個(gè)泛型會(huì)影響AsyncTask類中的哪幾個(gè)函數(shù)的參數(shù)和返回值

import android.os.AsyncTask;
public class DownLoadTask extends AsyncTask<String, Void, Boolean>{
    @Override
    protected Boolean doInBackground(String... params) {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
    }
    @Override
    protected void onProgressUpdate(Void... values) {
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);
    }   
}

Params:doInBackground的參數(shù)類型
Progress:onProgressUpdate的參數(shù)類型
Result:doInBackground的返回類型和onPostExecute參數(shù)類型


調(diào)用順序.png

我們首先來(lái)看下AsyncTask的構(gòu)造函數(shù),初始化兩個(gè)參數(shù)mWorker 和mFuture,mWorker是一個(gè)Callable對(duì)象,mFuture是一個(gè)FutureTask對(duì)象

  public AsyncTask() {
        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);
                }
            }
        };
    }

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

FutureTask 這個(gè)類在我們電腦上配置的JAVA環(huán)境中的 rt.jar

//      packname:java.util.concurrent
  public FutureTask(Callable<V> paramCallable)
  {
    if (paramCallable == null)
      throw new NullPointerException();
    this.callable = paramCallable;
    this.state = 0;
  }

把mWorker 保存在FutureTask 的callable 變量中。到這里,AsyncTask的初始化工作已經(jīng)完成。下面就是Task的啟動(dòng)execute方法

public final AsyncTask<Params, Progress, Result> execute(Params... params) {  
    return executeOnExecutor(sDefaultExecutor, params);  
}  
// private static volatile Executor sDefaultExecutor  =  new SerialExecutor();

接著看 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;
    }

函數(shù)中 首先會(huì)執(zhí)行onPreExecute(),可是doInBackground()是哪調(diào)用的呢,不用著急,我們慢慢找找,唯一可疑的就是exec.execute(mFuture);這個(gè)方法,我們點(diǎn)進(jìn)去看看。因?yàn)閑xec就是剛才傳進(jìn)去的sDefaultExecutor,而sDefaultExecutor又是SerialExecutor對(duì)象,所以這里調(diào)用的就是SerialExecutor的execute方法。

   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);
            }
        }
    }

仔細(xì)觀察上面的代碼,設(shè)計(jì)的很有意思,

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

SerialExecutor在AsyncTask以常量的形式被使用,因此整個(gè)應(yīng)用程序中的所有AsyncTask實(shí)例都會(huì)共用同一個(gè)SerialExecutor。SerialExecutor采用ArrayDeque這個(gè)隊(duì)列來(lái)維護(hù)添加進(jìn)的線程任務(wù)Runable.當(dāng)我們一次性執(zhí)行很多任務(wù)時(shí),第一次運(yùn)行會(huì)mActive 肯定等于null了,所以就調(diào)用scheduleNext函數(shù),

 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
允許在同一時(shí)刻有CORE_POOL_SIZE個(gè)任務(wù)正在執(zhí)行,并且最多能夠存儲(chǔ)MAXIMUM_POOL_SIZE個(gè)任務(wù)。

他會(huì)取出ArrayDeque的隊(duì)首的Runable給mActive ,然后執(zhí)行 THREAD_POOL_EXECUTOR.execute(mActive);去啟動(dòng)Runable的Run函數(shù),之后又有新的任務(wù)被offer到隊(duì)列中,這次mActive已然不等null,因?yàn)樗4媪说谝淮蔚奶砑舆M(jìn)來(lái)的Runable對(duì)象。但是呢,在run函數(shù)中有這么一段代碼
try {
r.run();
} finally {
scheduleNext();
}
每次執(zhí)行完Runable的任務(wù)后,都會(huì)去執(zhí)行scheduleNext()函數(shù),這就保證同一時(shí)刻只會(huì)有一個(gè)線程正在執(zhí)行,其余的均處于等待狀態(tài),是不是有點(diǎn)像單一線程池的效果。接下來(lái),可以知道execute開辟了一個(gè)線程Runnable 去執(zhí)行mFuture的run函數(shù)

  public void run()
  {
   .......
    try
    {
      Callable localCallable = this.callable;
      if ((localCallable != null) && (this.state == 0))
      {
        Object localObject1;
        int j;
        try
        {
          localObject1 = localCallable.call();
          j = 1;
        }
        catch (Throwable localThrowable)
        {
         ......
        }
        if (j != 0)
          set(localObject1);
      }
    }
    ......
  }

this.callable就是AsyncTask初始化創(chuàng)建的mWorker即WorkerRunnable對(duì)象,這里主要是調(diào)用了其call()函數(shù),再來(lái)看看WorkerRunnable的call函數(shù)到底做了哪些工作

 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);
            }
        };

這是AsyncTask構(gòu)造函數(shù)中的一段代碼,發(fā)現(xiàn)了沒有,里面執(zhí)行了doInBackground函數(shù)。到現(xiàn)在 我們把思路捋一下。
1、初始化AsyncTask的時(shí)候會(huì)創(chuàng)建mWorker和mFuture對(duì)象,在mFuture中會(huì)把mWorker當(dāng)做參數(shù)傳給mFuture的callable成員變量
2、執(zhí)行exec的時(shí)候會(huì)調(diào)用executeOnExecutor,然后在executeOnExecutor里面調(diào)用onPreExecute,exec.execute(mFuture);
3、SerialExecutor是AsyncTask的內(nèi)部靜態(tài)類。exec.execute(mFuture)會(huì)調(diào)用SerialExecutor的execute函數(shù),在這里面會(huì)開辟線程去執(zhí)行mFuture.run(),緊接著run函數(shù)調(diào)用mWorker的call函數(shù),進(jìn)而執(zhí)行doInBackground,經(jīng)過這幾步,不難doInBackground執(zhí)行在子縣城中,這就是為什么doInBackground可以執(zhí)行耗時(shí)操作的原因。
緊接著我們看postResult的源碼

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

熟悉android Handler機(jī)制的同學(xué)應(yīng)該會(huì)知道,這條消息最終會(huì)被getHandler()得到的Handler對(duì)象中handleMessage去處理

 private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

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;
            }
        }
    }

handleMessage中的消息有兩個(gè)類型

1.MESSAGE_POST_RESULT
  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

如果task沒有取消就調(diào)用onPostExecute,取消的話就執(zhí)行onCancelled

2.MESSAGE_POST_PROGRESS
protected final void publishProgress(Progress... values) {  
    if (!isCancelled()) {  
        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,  
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();  
    }  
}  

這也說(shuō)明在doInBackground中調(diào)用publishProgress可以總子線程切換到UI線程從而進(jìn)行UI線程的控件更新。
好了,AsyncTask的原理到這里就介紹完了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 線程池ThreadPoolExecutorJDK5帶來(lái)的一大改進(jìn)就是Java的并發(fā)能力,它提供了三種并發(fā)武器:并發(fā)...
    左上偏右閱讀 465評(píng)論 0 0
  • Android Handler機(jī)制系列文章整體內(nèi)容如下: Android Handler機(jī)制1之ThreadAnd...
    隔壁老李頭閱讀 3,419評(píng)論 1 15
  • AsyncTask在安卓中常用于線程間通信。在子線程執(zhí)行耗時(shí)任務(wù),在主線程更新UI。 AsyncTask內(nèi)部封裝了...
    著名的閱讀 228評(píng)論 0 3
  • 使用AsyncTask的一般步驟是: 定義一個(gè)類繼承自AsyncTask,實(shí)現(xiàn)抽象方法 new 一個(gè)AsyncTa...
    yk_looper閱讀 429評(píng)論 0 2
  • 消逝也是一種美吧,不信你看那天邊的晚霞。 人總是在幸福的時(shí)刻渴望永恒。窗外淅淅瀝瀝的小雨輕輕降臨在樹梢上、窗臺(tái)上,...
    平靜地平凡閱讀 436評(píng)論 2 1

友情鏈接更多精彩內(nèi)容