Android 源碼分析01_AsyncTask

【參考文獻】java

http://blog.csdn.net/singwhatiwanna/article/details/17596225android

 

  1 /*
  2  * Copyright (C) 2008 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package android.os;
 18 
 19 import java.util.ArrayDeque;
 20 import java.util.concurrent.BlockingQueue;
 21 import java.util.concurrent.Callable;
 22 import java.util.concurrent.CancellationException;
 23 import java.util.concurrent.Executor;
 24 import java.util.concurrent.ExecutionException;
 25 import java.util.concurrent.FutureTask;
 26 import java.util.concurrent.LinkedBlockingQueue;
 27 import java.util.concurrent.ThreadFactory;
 28 import java.util.concurrent.ThreadPoolExecutor;
 29 import java.util.concurrent.TimeUnit;
 30 import java.util.concurrent.TimeoutException;
 31 import java.util.concurrent.atomic.AtomicBoolean;
 32 import java.util.concurrent.atomic.AtomicInteger;
 33 
 34 public abstract class AsyncTask<Params, Progress, Result> {
 35     private static final String LOG_TAG = "AsyncTask";
 36 
 37     //獲取當前的cpu核心數
 38     private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
 39     //線程池核心容量
 40     private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
 41     //線程池最大容量
 42     private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
 43     //過剩的空閒線程的存活時間
 44     private static final int KEEP_ALIVE = 1;
 45     //ThreadFactory 線程工廠,經過工廠方法newThread來獲取新線程
 46     private static final ThreadFactory sThreadFactory = new ThreadFactory() {
 47         //原子整數,能夠在超高併發下正常工做
 48         private final AtomicInteger mCount = new AtomicInteger(1);
 49 
 50         public Thread newThread(Runnable r) {
 51             return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
 52         }
 53     };
 54     //靜態阻塞式隊列,用來存放待執行的任務,初始容量:128個
 55     private static final BlockingQueue<Runnable> sPoolWorkQueue =
 56             new LinkedBlockingQueue<Runnable>(128);
 57 
 58     /**
 59      * 靜態併發線程池,能夠用來並行執行任務,儘管從3.0開始,AsyncTask默認是串行執行任務
 60      * 可是咱們仍然能構造出並行的AsyncTask
 61      */
 62     public static final Executor THREAD_POOL_EXECUTOR
 63             = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
 64                     TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
 65 
 66     /**
 67      * 靜態串行任務執行器,其內部實現了串行控制,
 68      * 循環的取出一個個任務交給上述的併發線程池去執行
 69      */
 70     public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
 71     //消息類型:發送結果
 72     private static final int MESSAGE_POST_RESULT = 0x1;
 73     //消息類型:更新進度
 74     private static final int MESSAGE_POST_PROGRESS = 0x2;
 75     /**靜態Handler,用來發送上述兩種通知,採用UI線程的Looper來處理消息
 76      * 這就是爲何AsyncTask必須在UI線程調用,由於子線程
 77      * 默認沒有Looper沒法建立下面的Handler,程序會直接Crash
 78      */
 79     private static final InternalHandler sHandler = new InternalHandler();
 80     //默認任務執行器,被賦值爲串行任務執行器,就是它,AsyncTask變成串行的了
 81     private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
 82     //以下兩個變量咱們先不要深究,不影響咱們對總體邏輯的理解
 83     private final WorkerRunnable<Params, Result> mWorker;
 84     private final FutureTask<Result> mFuture;
 85     //任務的狀態 默認爲掛起,即等待執行,其類型標識爲易變的(volatile)
 86     private volatile Status mStatus = Status.PENDING;
 87     //原子布爾型,支持高併發訪問,標識任務是否被取消
 88     private final AtomicBoolean mCancelled = new AtomicBoolean();
 89     //原子布爾型,支持高併發訪問,標識任務是否被執行過
 90     private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
 91 
 92     /*串行執行器的實現,咱們要好好看看,它是怎麼把並行轉爲串行的
 93      *目前咱們須要知道,asyncTask.execute(Params ...)實際上會調用
 94      *SerialExecutor的execute方法,這一點後面再說明。也就是說:當你的asyncTask執行的時候,
 95      *首先你的task會被加入到任務隊列,而後排隊,一個個執行
 96      */
 97     private static class SerialExecutor implements Executor {
 98         //線性雙向隊列,用來存儲全部的AsyncTask任務
 99         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
100         //當前正在執行的AsyncTask任務
101         Runnable mActive;
102 
103         public synchronized void execute(final Runnable r) {
104             //將新的AsyncTask任務加入到雙向隊列中
105             mTasks.offer(new Runnable() {
106                 public void run() {
107                     try {
108                         //執行AsyncTask任務
109                         r.run();
110                     } finally {
111                         //當前AsyncTask任務執行完畢後,進行下一輪執行,若是還有未執行任務的話
112                         //這一點很明顯體現了AsyncTask是串行執行任務的,老是一個任務執行完畢纔會執行下一個任務
113                         scheduleNext();
114                     }
115                 }
116             });
117             //若是當前沒有任務在執行,直接進入執行邏輯
118             if (mActive == null) {
119                 scheduleNext();
120             }
121         }
122 
123         protected synchronized void scheduleNext() {
124             //從任務隊列中取出隊列頭部的任務,若是有就交給併發線程池去執行
125             if ((mActive = mTasks.poll()) != null) {
126                 THREAD_POOL_EXECUTOR.execute(mActive);
127             }
128         }
129     }
130 
131     /**
132      * 任務的三種狀態
133      */
134     public enum Status {
135         /**
136          * 任務等待執行
137          */
138         PENDING,
139         /**
140          * 任務正在執行
141          */
142         RUNNING,
143         /**
144          * 任務已經執行結束
145          */
146         FINISHED,
147     }
148 
149     /** 隱藏API:在UI線程中調用,用來初始化Handler */
150     public static void init() {
151         sHandler.getLooper();
152     }
153 
154     /** 隱藏API:爲AsyncTask設置默認執行器 */
155     public static void setDefaultExecutor(Executor exec) {
156         sDefaultExecutor = exec;
157     }
158 
159     /**
160      * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
161      */
162     public AsyncTask() {
163         mWorker = new WorkerRunnable<Params, Result>() {
164             public Result call() throws Exception {
165                 mTaskInvoked.set(true);
166 
167                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
168                 //noinspection unchecked
169                 return postResult(doInBackground(mParams));
170             }
171         };
172 
173         mFuture = new FutureTask<Result>(mWorker) {
174             @Override
175             protected void done() {
176                 try {
177                     postResultIfNotInvoked(get());
178                 } catch (InterruptedException e) {
179                     android.util.Log.w(LOG_TAG, e);
180                 } catch (ExecutionException e) {
181                     throw new RuntimeException("An error occured while executing doInBackground()",
182                             e.getCause());
183                 } catch (CancellationException e) {
184                     postResultIfNotInvoked(null);
185                 }
186             }
187         };
188     }
189 
190     private void postResultIfNotInvoked(Result result) {
191         final boolean wasTaskInvoked = mTaskInvoked.get();
192         if (!wasTaskInvoked) {
193             postResult(result);
194         }
195     }
196     //doInBackground執行完畢,發送消息
197     private Result postResult(Result result) {
198         @SuppressWarnings("unchecked")
199         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
200                 new AsyncTaskResult<Result>(this, result));
201         message.sendToTarget();
202         return result;
203     }
204 
205     /**
206      * 返回任務的狀態
207      */
208     public final Status getStatus() {
209         return mStatus;
210     }
211 
212     /**
213      * 這個方法是咱們必需要重寫的,用來作後臺計算
214      * 所在線程:後臺線程
215      */
216     protected abstract Result doInBackground(Params... params);
217 
218     /**
219      * 在doInBackground以前調用,用來作初始化工做
220      * 所在線程:UI線程
221      */
222     protected void onPreExecute() {
223     }
224 
225     /**
226      * 在doInBackground以後調用,用來接受後臺計算結果更新UI
227      * 所在線程:UI線程
228      */
229     protected void onPostExecute(Result result) {
230     }
231 
232     /**
233      * Runs on the UI thread after {@link #publishProgress} is invoked.
234      /**
235      * 在publishProgress以後調用,用來更新計算進度
236      * 所在線程:UI線程
237      */
238     protected void onProgressUpdate(Progress... values) {
239     }
240 
241      /**
242      * cancel被調用而且doInBackground執行結束,會調用onCancelled,表示任務被取消
243      * 這個時候onPostExecute不會再被調用,兩者是互斥的,分別表示任務取消和任務執行完成
244      * 所在線程:UI線程
245      */
246     @SuppressWarnings({"UnusedParameters"})
247     protected void onCancelled(Result result) {
248         onCancelled();
249     }    
250     
251     protected void onCancelled() {
252     }
253 
254     public final boolean isCancelled() {
255         return mCancelled.get();
256     }
257 
258     public final boolean cancel(boolean mayInterruptIfRunning) {
259         mCancelled.set(true);
260         return mFuture.cancel(mayInterruptIfRunning);
261     }
262 
263     public final Result get() throws InterruptedException, ExecutionException {
264         return mFuture.get();
265     }
266 
267     public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
268             ExecutionException, TimeoutException {
269         return mFuture.get(timeout, unit);
270     }
271 
272     /**
273      * 這個方法如何執行和系統版本有關,在AsyncTask的使用規則裏已經說明,若是你真的想使用並行AsyncTask,
274      * 也是能夠的,只要稍做修改
275      * 必須在UI線程調用此方法
276      */
277     public final AsyncTask<Params, Progress, Result> execute(Params... params) {
278         //串行執行
279         return executeOnExecutor(sDefaultExecutor, params);
280         //若是咱們想並行執行,這樣改就好了,固然這個方法咱們無法改
281         //return executeOnExecutor(THREAD_POOL_EXECUTOR, params);
282     }
283 
284     /**
285      * 經過這個方法咱們能夠自定義AsyncTask的執行方式,串行or並行,甚至能夠採用本身的Executor
286      * 爲了實現並行,咱們能夠在外部這麼用AsyncTask:
287      * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params);
288      * 必須在UI線程調用此方法
289      */
290     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
291             Params... params) {
292         if (mStatus != Status.PENDING) {
293             switch (mStatus) {
294                 case RUNNING:
295                     throw new IllegalStateException("Cannot execute task:"
296                             + " the task is already running.");
297                 case FINISHED:
298                     throw new IllegalStateException("Cannot execute task:"
299                             + " the task has already been executed "
300                             + "(a task can be executed only once)");
301             }
302         }
303 
304         mStatus = Status.RUNNING;
305         //這裏#onPreExecute會最早執行
306         onPreExecute();
307 
308         mWorker.mParams = params;
309         //而後後臺計算#doInBackground才真正開始
310         exec.execute(mFuture);
311         //接着會有#onProgressUpdate被調用,最後是#onPostExecute
312 
313         return this;
314     }
315 
316     /**
317      * 這是AsyncTask提供的一個靜態方法,方便咱們直接執行一個runnable
318      */
319     public static void execute(Runnable runnable) {
320         sDefaultExecutor.execute(runnable);
321     }
322 
323     /**
324      * 打印後臺計算進度,onProgressUpdate會被調用
325      */
326     protected final void publishProgress(Progress... values) {
327         if (!isCancelled()) {
328             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
329                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();
330         }
331     }
332 
333     //任務結束的時候會進行判斷,若是任務沒有被取消,則onPostExecute會被調用
334     private void finish(Result result) {
335         if (isCancelled()) {
336             onCancelled(result);
337         } else {
338             onPostExecute(result);
339         }
340         mStatus = Status.FINISHED;
341     }
342 
343     //AsyncTask內部Handler,用來發送後臺計算進度更新消息和計算完成消息
344     private static class InternalHandler extends Handler {
345         @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
346         @Override
347         public void handleMessage(Message msg) {
348             AsyncTaskResult result = (AsyncTaskResult) msg.obj;
349             switch (msg.what) {
350                 case MESSAGE_POST_RESULT:
351                     // There is only one result
352                     result.mTask.finish(result.mData[0]);
353                     break;
354                 case MESSAGE_POST_PROGRESS:
355                     result.mTask.onProgressUpdate(result.mData);
356                     break;
357             }
358         }
359     }
360 
361     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
362         Params[] mParams;
363     }
364 
365     @SuppressWarnings({"RawUseOfParameterizedType"})
366     private static class AsyncTaskResult<Data> {
367         final AsyncTask mTask;
368         final Data[] mData;
369 
370         AsyncTaskResult(AsyncTask task, Data... data) {
371             mTask = task;
372             mData = data;
373         }
374     }
375 }

一個例子git

  1 /**
  2  * 本類修改自 The Android Open SourceProject<br>
  3  * 使用高併發的線程池併發執行異步任務,用於替換Android自帶的AsyncTask,達到多線程執行的最大效率<br>
  4  * 使用適配器設計思想若是開發者須要使用串行執行Task任務,可手動調用
  5  * setDefaultExecutor(KJTaskExecutor.mSerialExecutor)方法<br>
  6  *
  7  * <b>優化點:</b>採用併發替代了系統的串行執行,同時修復了2.3以前並行執行大量數據是FC的問題。<br>
  8  * <b>建立時間</b> 2014-2-28 <br>
  9  * <b>修改時間</b> 2014-10-24 <br>
 10  *
 11  * @param <Params>
 12  *            啓動參數類型
 13  * @param <Progress>
 14  *            進度返回類型
 15  * @param <Result>
 16  *            結果返回類型
 17  * @author kymjs (https://github.com/kymjs)
 18  * @version 1.2
 19  */
 20 public abstract class KJAsyncTask<Params, Progress, Result> {
 21 
 22     private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
 23     private static final int CORE_POOL_SIZE = CPU_COUNT;// 長期保持活的躍線程數。
 24     private static final int MAXIMUM_POOL_SIZE = Integer.MAX_VALUE;// 線程池最大容量
 25     // 當前線程數大於活躍線程數時,此爲終止多餘的空閒線程等待新任務的最長時間
 26     private static final int KEEP_ALIVE = 10;
 27 
 28     private static final int MESSAGE_POST_RESULT = 0x1;// 消息類型:發送結果
 29     private static final int MESSAGE_POST_PROGRESS = 0x2;// 消息類型:更新進度
 30     private static final int MESSAGE_POST_FINISH = 0x3;// 消息類型:異步執行完成
 31     // 用來發送結果和進度通知,採用UI線程的Looper來處理消息 這就是爲何Task必須在UI線程調用
 32     private static final InternalHandler mHandler = new InternalHandler();
 33 
 34     // 工做線程
 35     private final WorkerRunnable<Params, Result> mWorker;
 36     // 待執行的runnable
 37     private final FutureTask<Result> mFuture;
 38     // 靜態阻塞式隊列,用來存放待執行的任務,初始容量:8個
 39     private static final BlockingQueue<Runnable> mPoolWorkQueue = new LinkedBlockingQueue<>(8);
 40     // 原子布爾型,支持高併發訪問,標識任務是否被取消
 41     private final AtomicBoolean mCancelled = new AtomicBoolean();
 42     // 原子布爾型,支持高併發訪問,標識任務是否被使用過
 43     private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
 44 
 45     private static OnFinishedListener finishedListener;
 46 
 47     // 任務的狀態 默認爲掛起,即等待執行,其類型標識爲易變的(volatile)
 48     private volatile Status mStatus = Status.PENDING;
 49 
 50     // 任務的三種狀態
 51     public enum Status {
 52         /** 任務等待執行 */
 53         PENDING,
 54         /** 任務正在執行 */
 55         RUNNING,
 56         /** 任務已經執行結束 */
 57         FINISHED
 58     }
 59 
 60     // ThreadFactory,經過工廠方法newThread來獲取新線程
 61     private static final ThreadFactory mThreadFactory = new ThreadFactory() {
 62         // 原子級整數,能夠在超高併發下正常工做
 63         private final AtomicInteger mCount = new AtomicInteger(1);
 64 
 65         @Override
 66         public Thread newThread(Runnable r) {
 67             return new Thread(r, "KJLibrary->KJTaskExecutor #" + mCount.getAndIncrement());
 68         }
 69     };
 70     /************************** 三種任務執行器的定義 *******************************/
 71 
 72     /**
 73      * 併發線程池任務執行器,它實際控制並執行線程任務,與mSerialExecutor(串行)相對應<br>
 74      * <b> 優化:</b> 不限制併發總線程數!讓任務總能獲得執行,且高效執行少許(不大於活躍線程數)的異步任務。<br>
 75      * 線程完成任務後保持10秒銷燬,這段時間內可重用以應付短期內較大量併發,提高性能。
 76      */
 77     public static final ThreadPoolExecutor mThreadPoolExecutor = new ThreadPoolExecutor(
 78             CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS,
 79             mPoolWorkQueue, mThreadFactory);
 80 
 81     /**
 82      * 併發量控制: 根據cpu能力控制一段時間內併發數量,併發過量大時採用Lru方式移除舊的異步任務,默認採用LIFO策略調度線程運做,
 83      * 開發者可選調度策略有LIFO、FIFO。
 84      */
 85     public static final Executor mLruSerialExecutor = new SmartSerialExecutor();
 86 
 87     /**
 88      * 串行任務執行器,其內部實現了串行控制, 循環的取出一個個任務交給上述的併發線程池去執行<br>
 89      * 與mThreadPoolExecutor(並行)相對應
 90      */
 91     public static final Executor mSerialExecutor = new SerialExecutor();
 92 
 93     // 設置默認任務執行器爲並行執行
 94     private static volatile Executor mDefaultExecutor = mLruSerialExecutor;
 95 
 96     /** 爲KJTaskExecutor設置默認執行器 */
 97     public static void setDefaultExecutor(Executor exec) {
 98         mDefaultExecutor = exec;
 99     }
100 
101     /**
102      * 建立一個asynchronous task,這個構造器必須運行於UI線程
103      */
104     public KJAsyncTask() {
105         mWorker = new WorkerRunnable<Params, Result>() {
106             @Override
107             public Result call() throws Exception {
108                 mTaskInvoked.set(true);
109                 // 設置線程優先級
110                 android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
111                 return postResult(doInBackground(mParams));
112             }
113         };
114 
115         mFuture = new FutureTask<Result>(mWorker) {
116             @Override
117             protected void done() {
118                 try {
119                     if (!mTaskInvoked.get()) {
120                         postResult(get());
121                     }
122                 } catch (InterruptedException e) {
123                 } catch (ExecutionException e) {
124                     throw new RuntimeException("An error occured while executing doInBackground()", e.getCause());
125                 } catch (CancellationException e) {
126                     if (!mTaskInvoked.get()) {
127                         postResult(null);
128                     }
129                 }
130             }
131         };
132     }
133 
134     /**
135      * doInBackground執行完畢,發送消息
136      *
137      * @param result
138      * @return
139      */
140     private Result postResult(Result result) {
141         @SuppressWarnings("unchecked")
142         Message message = mHandler.obtainMessage(MESSAGE_POST_RESULT, new KJTaskResult<Result>(this, result));
143         message.sendToTarget();
144         return result;
145     }
146 
147     /*********************** method ***************************/
148 
149     /**
150      * 耗時執行監聽器
151      *
152      * @return
153      */
154     public OnFinishedListener getFinishedListener() {
155         return finishedListener;
156     }
157 
158     /**
159      * 設置耗時執行監聽器
160      *
161      * @param finishedListener
162      */
163     public static void setOnFinishedListener(OnFinishedListener finishedListener) {
164         KJAsyncTask.finishedListener = finishedListener;
165     }
166 
167     /**
168      * 返回任務的狀態
169      */
170     public final Status getStatus() {
171         return mStatus;
172     }
173 
174     /**
175      * 返回該線程是否已經被取消
176      *
177      * @see #cancel(boolean)
178      */
179     public final boolean isCancelled() {
180         return mCancelled.get();
181     }
182 
183     /**
184      * 若是task已經執行完成,或被某些其餘緣由取消,再調用本方法將返回false;<br>
185      * 當本task尚未啓動就調用cancel(boolean),那麼這個task將歷來沒有運行,此時會返回true。<br>
186      * 若是任務已經啓動,則由參數決定執行此任務是否被中斷。<br>
187      *
188      * @param mayInterruptIfRunning
189      *            <tt>true</tt> 表示取消task的執行
190      * @return 若是線程不能被取消返回false, 好比它已經正常完成
191      */
192     public final boolean cancel(boolean mayInterruptIfRunning) {
193         mCancelled.set(true);
194         return mFuture.cancel(mayInterruptIfRunning);
195     }
196 
197     /**
198      * Waits if necessary for the computation to complete, and then retrieves
199      * its result.
200      *
201      * @return The computed result.
202      *
203      * @throws CancellationException
204      *             If the computation was cancelled.
205      * @throws ExecutionException
206      *             If the computation threw an exception.
207      * @throws InterruptedException
208      *             If the current thread was interrupted while waiting.
209      */
210     public final Result get() throws InterruptedException, ExecutionException {
211         return mFuture.get();
212     }
213 
214     /**
215      * Waits if necessary for at most the given time for the computation to
216      * complete, and then retrieves its result.
217      *
218      * @param timeout
219      *            Time to wait before cancelling the operation.
220      * @param unit
221      *            The time unit for the timeout.
222      *
223      * @return The computed result.
224      *
225      * @throws CancellationException
226      *             If the computation was cancelled.
227      * @throws ExecutionException
228      *             If the computation threw an exception.
229      * @throws InterruptedException
230      *             If the current thread was interrupted while waiting.
231      * @throws TimeoutException
232      *             If the wait timed out.
233      */
234     public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
235         return mFuture.get(timeout, unit);
236     }
237 
238     /*********************** start 一個完整的執行週期 ***************************/
239 
240     /**
241      * 在doInBackground以前調用,用來作初始化工做 所在線程:UI線程
242      */
243     protected void onPreExecute() {}
244 
245     /**
246      * 這個方法是咱們必需要重寫的,用來作後臺計算 所在線程:後臺線程
247      */
248     protected abstract Result doInBackground(Params... params);
249 
250     /**
251      * 打印後臺計算進度,onProgressUpdate會被調用<br>
252      * 使用內部handle發送一個進度消息,讓onProgressUpdate被調用
253      */
254     protected final void publishProgress(Progress... values) {
255         if (!isCancelled()) {
256             mHandler.obtainMessage(MESSAGE_POST_PROGRESS, new KJTaskResult<Progress>(this, values)).sendToTarget();
257         }
258     }
259 
260     /**
261      * 在publishProgress以後調用,用來更新計算進度 所在線程:UI線程
262      */
263     protected void onProgressUpdate(Progress... values) {}
264 
265     /**
266      * 任務結束的時候會進行判斷:若是任務沒有被取消,則調用onPostExecute;不然調用onCancelled
267      */
268     private void finish(Result result) {
269         if (isCancelled()) {
270             onCancelled(result);
271             if (finishedListener != null) {
272                 finishedListener.onCancelled();
273             }
274         } else {
275             onPostExecute(result);
276             if (finishedListener != null) {
277                 finishedListener.onPostExecute();
278             }
279         }
280         mStatus = Status.FINISHED;
281     }
282 
283     /**
284      * 在doInBackground以後調用,用來接受後臺計算結果更新UI 所在線程:UI線程
285      */
286     protected void onPostExecute(Result result) {}
287 
288     /**
289      * 所在線程:UI線程<br>
290      * doInBackground執行結束而且{@link #cancel(boolean)} 被調用。<br>
291      * 若是本函數被調用則表示任務已被取消,這個時候onPostExecute不會再被調用。
292      */
293     protected void onCancelled(Result result) {}
294 
295     /*********************** end 一個完整的執行週期 ***************************/
296     /*********************** core method ***************************/
297 
298     /**
299      * 這個方法必須在UI線程中調用<br>
300      * Note:這個函數將按照任務隊列去串行執行後臺線程或併發執行線程,這依賴於platform
301      * version,從1.6到3.0是並行,3.0之後爲串行(爲了不AsyncTask所帶來的併發錯誤), 若是你必定要並行執行,你能夠調用
302      * {@link #executeOnExecutor}替代這個方法,並將默認的執行器改成{@link #mThreadPoolExecutor}
303      *
304      * @param params
305      *            The parameters of the task.
306      * @return This instance of KJTaskExecutor.
307      * @throws IllegalStateException
308      *             If {@link #getStatus()} returns either
309      */
310     public final KJAsyncTask<Params, Progress, Result> execute(Params... params) {
311         return executeOnExecutor(mDefaultExecutor, params);
312     }
313 
314     /**
315      * 必須在UI線程調用此方法<br>
316      * 經過這個方法咱們能夠自定義KJTaskExecutor的執行方式,串行or並行,甚至能夠採用本身的Executor 爲了實現並行,
317      * asyncTask.executeOnExecutor(KJTaskExecutor.mThreadPoolExecutor, params);
318      */
319     public final KJAsyncTask<Params, Progress, Result> executeOnExecutor(
320             Executor exec, Params... params) {
321         if (mStatus != Status.PENDING) {
322             switch (mStatus) {
323                 case RUNNING:
324                     throw new IllegalStateException("Cannot execute task: the task is already running.");
325                 case FINISHED:
326                     throw new IllegalStateException("Cannot execute task: the task has already been executed(a task can be executed only once)");
327                 default:
328                     break;
329             }
330         }
331         mStatus = Status.RUNNING;
332         onPreExecute();
333         mWorker.mParams = params;
334         exec.execute(mFuture);// 原理{@link #execute(Runnable runnable)}
335         // 接着會有#onProgressUpdate被調用,最後是#onPostExecute
336         return this;
337     }
338 
339     /**
340      * 提供一個靜態方法,方便在外部直接執行一個runnable<br>
341      * 用於瞬間大量併發的場景,好比,假設用戶拖動ListView時若是須要啓動大量異步線程,而拖動過去時間好久的用戶已經看不到,容許任務丟失。
342      */
343     public static void execute(Runnable runnable) {
344         mDefaultExecutor.execute(runnable);
345     }
346 
347     /**
348      * KJTaskExecutor內部Handler,用來發送後臺計算進度更新消息和計算完成消息
349      */
350     private static class InternalHandler extends Handler {
351         @Override
352         @SuppressWarnings({ "unchecked", "rawtypes" })
353         public void handleMessage(Message msg) {
354             KJTaskResult result = (KJTaskResult) msg.obj;
355             switch (msg.what) {
356                 case MESSAGE_POST_RESULT:
357                     result.mTask.finish(result.mData[0]);
358                     break;
359                 case MESSAGE_POST_PROGRESS:
360                     result.mTask.onProgressUpdate(result.mData);
361                     break;
362                 case MESSAGE_POST_FINISH:
363                     if (finishedListener != null) {
364                         finishedListener.onPostExecute();
365                     }
366                     break;
367             }
368         }
369     }
370 
371     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
372         Params[] mParams;
373     }
374 
375     private static class KJTaskResult<Data> {
376         final Data[] mData;
377         final KJAsyncTask<?, ?, ?> mTask;
378 
379         KJTaskResult(KJAsyncTask<?, ?, ?> task, Data... data) {
380             mTask = task;
381             mData = data;
382         }
383     }
384 
385     /**
386      * 串行執行器的實現<br>
387      * 若是採用串行執行,asyncTask.execute(Params ...)實際上會調用 SerialExecutor的execute方法。
388      * {@link #executeOnExecutor}
389      */
390     private static class SerialExecutor implements Executor {
391         // 線性雙向隊列,用來存儲全部的AsyncTask任務
392         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
393         /** 當前正在執行的AsyncTask任務 */
394         Runnable mActive = null;
395 
396         @Override
397         public synchronized void execute(final Runnable r) {
398             // 將task任務加入到SerialExecutor的雙向隊列中,也就是讓task排隊執行
399             mTasks.offer(new Runnable() {
400                 @Override
401                 public void run() {
402                     try {
403                         r.run();
404                     } finally {
405                         // 當前task執行完畢後,安排下一個執行
406                         scheduleNext();
407                     }
408                 }
409             });
410             // 若是當前沒有任務在執行,直接進入執行邏輯
411             if (mActive == null) {
412                 scheduleNext();
413             }
414         }
415 
416         /**
417          * 相似適配器設計模式,若是是並行執行任務就不調用上面的方法而直接使用併發執行者執行任務<br>
418          * 若是是串行執行任務, 就配合上面的函數將本來是併發執行的代碼轉換成串行執行
419          */
420         protected synchronized void scheduleNext() {
421             // 從任務隊列中取出隊列頭部的任務,若是有就交給併發線程池去執行
422             if ((mActive = mTasks.poll()) != null) {
423                 mThreadPoolExecutor.execute(mActive);
424             }
425         }
426     }
427 
428     /**
429      * 用於替換掉原生的mThreadPoolExecutor,能夠大大改善Android自帶異步任務框架的處理能力和速度。
430      * 默認使用LIFO(後進先出)策略來調度線程,可將最新的任務快速執行,固然你本身能夠換爲FIFO調度策略。
431      * 這有助於用戶當前任務優先完成(好比加載圖片時,很容易作到當前屏幕上的圖片優先加載)。
432      */
433     private static class SmartSerialExecutor implements Executor {
434         /**
435          * 這裏使用{@link ArrayDeque}做爲棧比{@link Stack}性能高
436          */
437         private final ArrayDeque<Runnable> mQueue = new ArrayDeque<Runnable>(serialMaxCount);
438         private final ScheduleStrategy mStrategy = ScheduleStrategy.LIFO;
439 
440         private enum ScheduleStrategy {
441             LIFO, FIFO
442         }
443 
444         /**
445          * 一次同時併發的數量,根據處理器數量調節 <br>
446          * cpu count : 1 2 3 4 8 16 32 <br>
447          * once(base*2): 1 2 3 4 8 16 32 <br>
448          * 一個時間段內最多併發線程個數: 雙核手機:2 四核手機:4 ... 計算公式以下:
449          */
450         private static int serialOneTime;
451         /**
452          * 併發最大數量,當投入的任務過多大於此值時,根據Lru規則,將最老的任務移除(將得不到執行) <br>
453          * cpu count : 1 2 3 4 8 16 32 <br>
454          * base(cpu+3) : 4 5 6 7 11 19 35 <br>
455          * max(base*16): 64 80 96 112 176 304 560 <br>
456          */
457         private static int serialMaxCount;
458 
459         private void reSettings(int cpuCount) {
460             serialOneTime = cpuCount;
461             serialMaxCount = (cpuCount + 3) * 16;
462         }
463 
464         public SmartSerialExecutor() {
465             reSettings(CPU_COUNT);
466         }
467 
468         @Override
469         public synchronized void execute(final Runnable command) {
470             Runnable r = new Runnable() {
471                 @Override
472                 public void run() {
473                     command.run();
474                     next();
475                     mHandler.sendEmptyMessage(MESSAGE_POST_FINISH);
476                 }
477             };
478             if ((mThreadPoolExecutor).getActiveCount() < serialOneTime) {
479                 // 小於單次併發量直接運行
480                 mThreadPoolExecutor.execute(r);
481             } else {
482                 // 若是大於併發上限,那麼移除最老的任務
483                 if (mQueue.size() >= serialMaxCount) {
484                     mQueue.pollFirst();
485                 }
486                 // 新任務放在隊尾
487                 mQueue.offerLast(r);
488             }
489         }
490 
491         public synchronized void next() {
492             Runnable mActive;
493             switch (mStrategy) {
494                 case LIFO:
495                     mActive = mQueue.pollLast();
496                     break;
497                 case FIFO:
498                     mActive = mQueue.pollFirst();
499                     break;
500                 default:
501                     mActive = mQueue.pollLast();
502                     break;
503             }
504             if (mActive != null) {
505                 mThreadPoolExecutor.execute(mActive);
506             }
507         }
508     }
509 
510     public static abstract class OnFinishedListener {
511         public void onCancelled() {}
512 
513         public void onPostExecute() {}
514     }
515 }
相關文章
相關標籤/搜索