三流之路有沒有第二部,Android源碼之路(二、AsyncTask)

 2023-10-07 阅读 21 评论 0

摘要:參考 https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErtRW7VD-sNEgCRNespIhSK&wd=&eqid=9a27957100030dcd000000065aac77c0 https://www.jianshu.com/p/79cc3c5fc9a3 三流之路有沒有第二部,http://bl

參考

https://www.baidu.com/link?url=QNRznJEBT25k0bpgVD3bOniOia2W85eiPIWrS93YFknyrHoFDGrJVtoax2ZYpiiErtRW7VD-sNEgCRNespIhSK&wd=&eqid=9a27957100030dcd000000065aac77c0

https://www.jianshu.com/p/79cc3c5fc9a3

三流之路有沒有第二部,http://blog.csdn.net/majihua817/article/details/51658465

以下用法和源碼分析基于android-27(即版本android 8.1.0)

要點總結:

1.進程所有AsyncTask默認并不是并行執行的,通常默認的?使用execute執行?的AsyncTask是排隊按順序執行的,同一時間內只有一個AsyncTask會運行;

2.進程中使用executeOnExecutor(Executor exec,Params...params)根據傳入的線程池效果,可以實現同一時間多個AsyncTask異步執行的效果;

android源碼,3.常用的回調方法有:onPreExecute()、doInBackground(Params... params)、onProgressUpdate(Progress... values)、onPostExecute(Result result)

  • a. 執行順序為onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute

  • b. onPreExecute: 運行在ui線程,當代碼執行AsyncTask.execute(Params...params)后會被調用,一般可用于界面上一些初始化操作,比如彈出下載對話框等;

  • c. doInBackground:運行在后臺非ui線程,用來處理耗時的任務,如下載、數據處理等;

  • Android 編譯、d. onProgressUpdate:運行在ui線程,可用來處理界面上的一些進度更新相關操作;在doInBackground中調用publishProgress后,可觸發onProgressUpdate;

  • e. 當然onPreExecute也可以使用publishProgress觸發onProgressUpdate,只是二者都是ui線程,所以并沒有實際意義;

  • f. 注意的是publishProgress也是使用的handler發送消息來觸發的onProgressUpdate,所以注意的是
    doInBackground沒人為干預的話并不會因此堵塞等待onProgressUpdate執行完畢

  • g. onPostExecute:運行在ui線程,可用于界面提示操作完成,在doInBackground執行完使用return后調用;

  • 安卓源碼。h.源碼中對這些重要回調方法都有對應的@MainThread、@WorkerThread線程注解,但這個注解目前主要用于IDE編譯檢查錯誤用的,實際上execute等依舊可以在子線程中調用,當然onPreExecute此時就不能處理ui界面,否則會拋出異常;但建議調用的地方和注解一致

4.執行過一個次或者正在執行的AsyncTask不能再次通過execute或者executeOnExecutor進行重復執行

5.使用executeOnExecutor并行執行的話,根據傳入的線程池的設置會有隊列大小的限制,通常直接使用AsyncTask中AsyncTask.THREAD_POOL_EXECUTOR這個線程池的話:

//cpu核數,假設4
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 
//核心線程數,3
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大同時執行的線程數9   
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空閑線程超過30秒被回收
private static final int KEEP_ALIVE_SECONDS = 30;               
//等待隊列允許的最大數量為128
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;

(假設終端cpu數目為4)因為該線程池運行同時運行的最大線程數為9,等待隊列最大為128,如果每一個asynctask的doInBackground中耗時非常久,一次性添加超過9+128=137個task的話(比如listview中一次性創建),那么將會引起異常java.util.concurrent.RejectedExecutionException

中二之路。6.使用execute的話,因為有隊列緩存(沒大小限制,除非內存爆掉),串行執行,所以不存在線程池中任務超出大小的情況

7.AsyncTaskd的cancel方法只是簡單把標志位改為true,最后使用Thread.interrupt去中斷線程執行,但是這并不保證會馬上停止執行,所以可以在doInBackground中使用isCancelled來判斷任務是否被取消

要點解釋

(來自參考資料https://www.jianshu.com/p/79cc3c5fc9a3)

三流之路的女兒?在Android 1.5剛引入的時候,AsyncTask的execute是串行執行的;到了Android 1.6直到Android 2.3.2,又被修改為并行執行了,這個執行任務的線程池就是THREAD_POOL_EXECUTOR,因此在一個進程內,所有的AsyncTask都是并行執行的;但是在Android 3.0以后,如果你使用execute函數直接執行AsyncTask,那么這些任務是串行執行的。因此結論就來了:Android 3.0以上,AsyncTask默認并不是并行執行的。

由于同一個進程的AsyncTask都是在一個線程池中,如果默認是并行的,那么多個線程同時執行多個task中的doInBackground操作,而doInBackground又訪問修改相同的資源,這邊往往會忽略對資源的同步處理問題,經常會導致不可預料的錯誤結果,為此默認情況下使用execute執行的AsyncTask默認為串行執行;

如果處理好資源同步問題,可以使用executeOnExecutor傳入合適的線程池,來達到AsyncTask并行執行的效果;

優缺點總結

優點:

  • 1.封裝后實現簡單的的子線程和ui線程間的一個切換,省去了用戶需要子線程更新ui界面繁瑣的操作

簡述android源代碼編譯過程?缺點(參考http://blog.csdn.net/goodlixueyong/article/details/45895997):

  • 1.需要注意串行還是并行執行,在1.5是串行,1.6-2.3.2是并行,3.0之后默認使用execute時串行,如果使用executeOnExecutor則是并行;

  • 2.所謂的串行,實際上主要是針對doInBackground方法里面的操作而言的,串行時并不會等到task中onPostExecute執行完才觸發下一份asynctask,只要doInBackground執行完成就會促發下一個asynctask

  • 3.可能導致內存泄露或者ui更新異常問題,如果是activity中非靜態內部asynctask子類,默認隱式持有一個activity的引用,在activity銷毀之前,注意要停止asynctask;不然后臺線程一直運行,導致了內存泄露,還可能在要更新ui時,該view已經不存在而導致異常;

  • android應用源碼、4.如果activity因為轉屏重建或者被后臺異常終結,之前運行的asynctask還會持有一個之前activity的引用,更新這個無效的引用上的view需要注意對view有效性的判斷

  • 5.并行執行的時候,需要考慮下線程池能夠處理的任務大小

使用方法

聲明MyAsyncTask繼承并實現AsyncTask相關回調:

    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{String TAG="MyAsyncTask";public MyAsyncTask(String tag) {super();this.TAG=tag;}//doInBackground開始之前調用,ui線程,可用于界面上的一些初始化操作,比如彈出下載對話框@Overrideprotected void onPreExecute() {Log.d(TAG,"onPreExecute "+Thread.currentThread());Toast.makeText(context,"onPreExecute",Toast.LENGTH_SHORT).show();}//用于執行后臺任務,非ui線程,用于處理耗時任務,下載,數據處理等@Overrideprotected Boolean doInBackground(String... params) {Log.d(TAG,"doInBackground "+Thread.currentThread());int count = params.length;for(int i=0;i<count;i++){//判斷任務是否取消,取消則停止,用戶調用AsyncTask.cancel()后設置該標志位//調用AsyncTask.cancel()并不能直接停止一個asynctask,// 需要在doInBackground/onProgressUpdate/onPreExecute手動判斷該標志位if(isCancelled()){return false}String p = params[i];Log.d(TAG,"doInBackground:"+p);publishProgress(i);}return true;}//當后臺任務doInBackground調用了publishProgress(Progress...)方法后,這個方法會被調用//用于執行處理過程中的進度更新之類,ui線程,可用于更新下載對話框的進度條@Overrideprotected void onProgressUpdate(Integer... values) {Log.d(TAG,"onProgressUpdate:"+values[0]+"  "+Thread.currentThread());Toast.makeText(context,"onProgressUpdate:"+values[0],Toast.LENGTH_SHORT).show();}//當后臺任務doInBackground執行完畢并通過return語句進行返回時,這個方法就會被調用//ui線程,可用于界面更新處理完成@Overrideprotected void onPostExecute(Boolean aBoolean) {Log.d(TAG,"onPostExecute:"+aBoolean+"  "+Thread.currentThread());Toast.makeText(context,"onPostExecute",Toast.LENGTH_SHORT).show();}//AsyncTaskd的cancel方法只是簡單把標志位改為true,最后使用Thread.interrupt去中斷線程執行,但是這并不保證會馬上停止執行,所以可以在doInBackground中使用isCancelled來判斷任務是否被取消//ui線程,可用于取消后關閉ui界面提示等@Overrideprotected void onCancelled(Boolean aBoolean) {Log.d(TAG,"onCancelled:"+aBoolean+"  "+Thread.currentThread());}}

創建相關實例并執行AsyncTask:

測試一:普通使用

    Log.d(TAG,"btn1 start");MyAsyncTask myAsyncTask =new MyAsyncTask("task1"); //創建AsyncTask子類實例myAsyncTask.execute("參數1","參數2");      //開始執行Log.d(TAG,"btn1 end");**日志輸出**:btn1 start                              onPreExecute Thread[main,5,main]      //可以看見調用execute后,onPreExecute立馬執行btn1 enddoInBackground Thread[AsyncTask #1,5,main]   doInBackground:參數1doInBackground:參數2//doInBackground調用publishProgress后,由handler觸發onProgressUpdate,與doInBackground為2個線程異步執行onProgressUpdate:0  Thread[main,5,main]  onProgressUpdate:1  Thread[main,5,main]onPostExecute:true  Thread[main,5,main] //全部操作完成后調用

測試二:多個asyncTask使用驗證串行執行

    Log.d(TAG,"btn1 start");MyAsyncTask myAsyncTask =new MyAsyncTask("task1");MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");myAsyncTask.execute("參數1","參數2");myAsyncTask2.execute("參數1","參數2");Log.d(TAG,"btn1 end");日志輸出:btn1 start//可以看見各自調用execute后,task1,task2的onPreExecute立馬執行,互不影響task1: onPreExecute Thread[main,5,main] task2: onPreExecute Thread[main,5,main]btn1 endtask1: doInBackground Thread[AsyncTask #1,5,main] //doInBackground是按序執行的task1: doInBackground:參數1task1: doInBackground:參數2task2: doInBackground Thread[AsyncTask #2,5,main]task2: doInBackground:參數1task2: doInBackground:參數2//onProgressUpdate和onProgressUpdate也是按序執行的//這邊看到可能存在后續asyncTask執行doInBackground過程中,前面的task才剛觸發onProgressUpdate和onPostExecutetask1: onProgressUpdate:0  Thread[main,5,main]   task1: onProgressUpdate:1  Thread[main,5,main]  task1: onPostExecute:true  Thread[main,5,main]task2: onProgressUpdate:0  Thread[main,5,main]task2: onProgressUpdate:1  Thread[main,5,main]task2: onPostExecute:true  Thread[main,5,main]

測試三:并行執行:

MyAsyncTask myAsyncTask =new MyAsyncTask("task1");MyAsyncTask myAsyncTask2 =new MyAsyncTask("task2");myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"參數1","參數2");myAsyncTask2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"參數1","參數2");日志輸出(doInBackground 添加Thread.sleep方便模擬):btn1 starttask1: onPreExecute Thread[main,5,main]task2: onPreExecute Thread[main,5,main]//task1與task2的doInBackground部分交替執行task1: doInBackground Thread[AsyncTask #1,5,main]task1: doInBackground:參數1                             task2: doInBackground Thread[AsyncTask #2,5,main]task2: doInBackground:參數1                             btn1 endtask1: onProgressUpdate:0  Thread[main,5,main]task2: onProgressUpdate:0  Thread[main,5,main]task1: doInBackground:參數2task2: doInBackground:參數2task1: onProgressUpdate:1  Thread[main,5,main]task2: onProgressUpdate:1  Thread[main,5,main]task1: onPostExecute:true  Thread[main,5,main]task2: onPostExecute:true  Thread[main,5,main]

從測試中可以看出onPreExecute在各自AsyncTask調用execute后立即執行,后續源碼分析可知道onPreExecute不由handler觸發,否則可能與doInBackground執行時序有差別;

測試二中:
后續從源碼分析可以知道使用execute觸發的AsyncTask中的doInBackground部分實際上是在線程池中排隊執行的,所以只有一個任務的doInBackground執行完,才會獲取下一個任務的doInBackground進行執行;

從源碼分析可以知道onProgressUpdate、onPostExecute是通過handler消息控制的,本身也是按序執行的;多個AsyncTask的不同的生命周期步驟其實會有穿插;

從日志輸出和源碼原理可知,AsyncTask的按序執行相對來講有一定的不足,不會等待一個AsyncTask完整執行完后onPreExecute -> doInBackground--> (onProgressUpdate)->onPostExecute,后下一個AsyncTask才允許開始它的生命周期;

測試三中:
驗證了執行線程池并行執行的效果


源碼分析

AsyncTask開始執行工作的入口函數為AsyncTask.execute,所以從該方法入手查看

AsyncTask源碼

execute函數

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);
}注解上也表明該方法運行需要在ui線程運行,為什么需要呢?此為問題一;這邊使用execute觸發會使用默認的線程池SerialExecutor sDefaultExecutor,
該線程池實際上只起到一個隊列控制,保存task依次按順序執行;
假設需要并發執行AsyncTask,則可以直接使用executeOnExecutor方法
傳入合適的線程池就可以達到效果;接著查看調用的executeOnExecutor所執行的操作

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;
}
  • 首先該方法會進行一個AsyncTask狀態的判斷,如果該AsyncTask已經運行過或者正在運行則拋出異常,
    每個AsyncTask只允許直接或者間接調用一次executeOnExecutor;

  • 狀態判斷AsyncTask尚處于等待狀態Status.PENDING,則將該狀態標識為Status.RUNNING正在運行狀態等待后續線程池排隊執行;

  • 注意,接著立即執行onPreExecute()方法,也就是用于初始化ui控件準備工作的方法;
    這邊說明了前面2個問題:

    • 1、onPreExecute()方法在execute()方法調用后會立即執行;
    • 2、execute()假設在非ui線程調用,則onPreExecute()也在非ui線程執行,將導致拋出更新ui異常,此為上述問題一,需要要求execute或或者executeOnExecutor在ui線程執行;
    • 3、雖然注解和源碼注釋要求要在ui線程執行execute()或者executeOnExecutor,但假設你沒有重寫onPreExecute()進行ui操作(默認是空操作),是可以在子線程中執行的(可能IDE會有提示錯誤,但運行的時候沒出現異常),當然強烈建議執行線程和注解一致
    mWorker.mParams = params;exec.execute(mFuture);

然后將傳入的params參數賦值給mWorker.mParams(params后續會傳遞給doInBackground進行處理),調用線程池exec處理mFuture;

這邊需要對mWorker、mFuture和線程池exec進行分析,首先對于exec可以看出傳入的是線程池SerialExecutor

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

對于線程池SerialExecutor

  • 通過上述分析知道SERIAL_EXECUTOR的定義是靜態的,也就是類共享的,同一進程共用一個線程池,
  • 下面分析會知道SERIAL_EXECUTOR主要用來維護asynctask任務隊列,按先進先出的原則順序取出任務交給實際執行的線程池THREAD_POOL_EXECUTOR進行執行
  • 對于THREAD_POOL_EXECUTOR也是靜態的,并且執行完一個后才會處理下一個任務;
  • 因此如果同時創建多個AsyncTask后使用execute進行執行,默認是加入到SERIAL_EXECUTOR進行排隊等待執行的,一個時刻只有一個AsyncTask在執行;
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;private static final ThreadFactory sThreadFactory = new ThreadFactory() {private final AtomicInteger mCount = new AtomicInteger(1);public Thread newThread(Runnable r) {return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());}
};//實際執行任務的線程池,注意是靜態的,所以AsyncTask共用
public static final Executor THREAD_POOL_EXECUTOR;
static {ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,sPoolWorkQueue, sThreadFactory);threadPoolExecutor.allowCoreThreadTimeOut(true);THREAD_POOL_EXECUTOR = threadPoolExecutor;
}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();        //即調用 FutureTask mFuture.run()方法    } finally {scheduleNext();}}});if (mActive == null) {scheduleNext();}}protected synchronized void scheduleNext() {if ((mActive = mTasks.poll()) != null) {//THREAD_POOL_EXECUTOR為實際執行任務的線程池THREAD_POOL_EXECUTOR.execute(mActive);}}}

可以看出該SerialExecutor在被調用execute后,會將一個任務添加到隊列ArrayDeque中(即前面exec.execute(mFuture)),execute傳入的是實現了Runnable接口的類FutureTask的實例mFuture,SerialExecutor的主要作用實際上時維護任務的隊列,按順序取出任務交給實際執行任務的線程池THREAD_POOL_EXECUTOR

第一個執行時mActive == null所以會調用scheduleNext,(按先進先出)從隊列中拿出一個任務交給線程池THREAD_POOL_EXECUTOR進行執行:

  public void run() {try {r.run();        //即調用 FutureTask mFuture.run()方法    } finally {scheduleNext(); //執行完畢后,獲取下一個任務進行處理}}

執行的即為傳入的mFuture.run()方法,執行完成后會再次調用scheduleNext獲取并執行下一個AsyncTask任務。
下面看一下FutureTask.run()方法所做的操作

FutureTask類

//FutureTask類構造函數,這邊傳入的實際上是實現了Callable接口的WorkerRunnable類對象mWorker
//mWorker與mFuture的關聯在AsyncTask創建時構造函數中完成
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable
}//線程池THREAD_POOL_EXECUTOR中執行的方法
public void run() {if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return;try {Callable<V> c = callable;       if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();   //調用的是mWorker的call方法ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}
}

由上述可知,線程池THREAD_POOL_EXECUTOR中執行的mFuture.run()方法中實際上會調用result = c.call()即實現了Callable接口的類的WorkerRunnable對象mWorker.call();

其中WorkerRunnable類對象mWorker、FutureTask類對象mFuture的創建和關聯位于AsyncTask構造函數中;

AsyncTask構造函數

    //部分需要聯系使用的成員變量//注意是靜態的,類共享一個線程池private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//注意是靜態的變量,類共享一個handlerprivate static InternalHandler sHandler;                        private final WorkerRunnable<Params, Result> mWorker;private final FutureTask<Result> mFuture;private final Handler mHandler;/*** Creates a new asynchronous task. This constructor must be invoked on the UI thread.*/public AsyncTask() {this((Looper) null);}/*** Creates a new asynchronous task. This constructor must be invoked on the UI thread.** @hide*/public AsyncTask(@Nullable Handler handler) {this(handler != null ? handler.getLooper() : null);}/*** Creates a new asynchronous task. This constructor must be invoked on the UI thread.** @hide*/public AsyncTask(@Nullable Looper callbackLooper) {mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()? getMainHandler(): new Handler(callbackLooper);mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams); //線程池中最終執行doInBackgroundBinder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}return result;}};mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected 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);}}};}

由上可以看出默認構造函數會執行

public AsyncTask(@Nullable Looper callbackLooper),傳入參數為null,
此時mHandler = getMainHandler()獲取到一個主線程的handler;
創建了mWorker和mFuture對象,并通過mFuture = new FutureTask<Result>(mWorker)
完成mFuture與mWorker的一個關聯;

后續,線程池THREAD_POOL_EXECUTOR中執行的mFuture.run()會執行到mWorker.call()由上可看出:

    try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams); //線程池中最終執行doInBackgroundBinder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}

觸發執行了doInBackground(mParams)后,通過postResult(result)將結果result通過hander發出最終在handler的ui線程中觸發了onPostExecute回調;

postResult函數

private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}
使用handler發送處理結束的消息

getMainHandler函數

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

該方法簡單的創建一個handler通過Looper.getMainLooper()使得該handler運行于ui線程,注意的是sHandler是靜態的,也就是說進程所有的AsyncTask共享一個handler進行處理消息;

InternalHandler類和finish方法

private static class InternalHandler extends Handler {public InternalHandler(Looper looper) {super(looper);}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {//接收消息并且在ui線程回調執行finish最終調用onPostExecute方法case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;//接收消息并且在ui線程回調執行onProgressUpdate方法case MESSAGE_POST_PROGRESS:    result.mTask.onProgressUpdate(result.mData);break;}}}
  • 該handler主要用于接收消息MESSAGE_POST_PROGRESS后在ui線程執行onProgressUpdate方法,
    或者接收MESSAGE_POST_RESULT后,最終在ui線程執行onPostExecute/onCancelled方法,

  • AsyncTask中2個重要的方法onProgressUpdate、onPostExecute由該handler執行;

    private void finish(Result result) {if (isCancelled()) {//任務執行完之后,如果用戶之前調用了AsyncTask.cancle()則觸發onCancelledonCancelled(result);} else {//否則觸發onPostExecuteonPostExecute(result);  }mStatus = Status.FINISHED;}

源碼總結

  • 1.AsyncTask中存在靜態的2個線程池SerialExecutor、ThreadPoolExecutor,以及一個靜態的ui線程的handler
SerialExecutor implements Executor :    sDefaultExecutor
ThreadPoolExecutor :                    THREAD_POOL_EXECUTOR:
進程中對于使用execute開始的所有的AsyncTask順序排隊執行
  • 2.AsyncTask構造函數中,初始化了handler,WorkerRunnable mWorker,FutureTask mFuture,并且將mWorker關聯到mFuture:
  mWorker = new WorkerRunnable<Params, Result>(){..}..mFuture = new FutureTask<Result>(mWorker) {..}..
  • 3.使用execute的時候:

    • 會調用executeOnExecutor()并傳遞SerialExecutor
    • 在executeOnExecutor()中執行onPreExecute,并將mFuture傳遞給SerialExecutor進行排隊
    • SerialExecutor按先進先出的順序依次取出任務給ThreadPoolExecutor進行處理,處理調用的是mFuture.run()方法實際上會執行到mWorker.call()里面的doInBackground方法,執行完成后通過handler觸發onPostExecute方法;
  • 過程中如果調用publishProgress會通過handler觸發onProgressUpdate;

  • 如果要并行執行asynctask則不使用execute而是直接使用executeOnExecutor傳遞給合適的線程池,跳過SerialExecutor的排隊步驟;

掃描關注微信公眾號:

?

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/126646.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息