Android 源码分析01_AsyncTask

【参考文献】

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

 

  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 }

一个例子

  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 }

 

posted @ 2015-11-02 16:38  壬子木  阅读(308)  评论(0编辑  收藏  举报