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 }
时间: 2024-10-18 01:04:40

Android 源码分析01_AsyncTask的相关文章

Cordova Android源码分析系列一(项目总览和CordovaActivity分析)

PhoneGap/Cordova是一个专业的移动应用开发框架,是一个全面的WEB APP开发的框架,提供了以WEB形式来访问终端设备的API的功能.这对于采用WEB APP进行开发者来说是个福音,这可以避免了原生开发的某些功能.Cordova 只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用. Cordova Android项目是Cordova Android原生部分的Java代码实现,提供了Android原生代码和上层We

Android 源码分析工具

标 题: [原创]Android源码分析工具及方法作 者: MindMac时 间: 2014-01-02,09:32:35链 接: http://bbs.pediy.com/showthread.php?t=183278 在对 Android 源码进行分析时,如果有得力的工具辅助,会达到事半功倍的效果.本文介绍了一些在分析 Android 源码时使用的一些工具和方法,希望能够帮助到有需要的同学. Eclipse 在 Android 应用程序开发过程中,一般会使用 Eclipse,当然 Googl

Android源码分析:Telephony部分–GSMPhone

Android源码分析:Telephony部分–GSMPhone红狼博客 PhoneProxy/GSMPhone/CDMAPhone 如果说RILJ提供了工具或管道,那么Phone接口的子类及PhoneFactory则为packages/app/Phone这个应用程序进程使用RILJ这个工具或管道提供了极大的方便,它们一个管理整个整个手机的Telephony功能. GSMPhone和CDMAPhone实现了Phone中定义的接口.接口类Phone定义了一套API,这套API用于使用RILJ(见后

Android源码分析:Telephony部分–phone进程

Android源码分析:Telephony部分–phone进程红狼博客 com.android.phone进程 它就象个后台进程一样,开机即运行并一直存在.它的代码位于:packages/apps/Phone/src/com/android/phone 当有来电时,它会作出反应,如显示UI和铃声提示:当在通话过程中,它显示InCallScreen: 当要拨号时ITeleohony的接口调用最终到Phone进程,然后由它去与PhoneFactory创建的GSMPhone或CDMAPhone进行交互

Android源码分析之SparseArray

本来接下来应该分析MessageQueue了,可是我这几天正好在实际开发中又再次用到了SparseArray(之前有用到过一次,那次只是 大概浏览了下源码,没做深入研究),于是在兴趣的推动下,花了些时间深入研究了下,趁着记忆还是新鲜的,就先在这里分析了. MessageQueue的分析应该会在本周末给出. 和以往一样,首先我们来看看关键字段和ctor: private static final Object DELETED = new Object(); private boolean mGar

Android源码分析之SharedPreferences

在Android的日常开发中,相信大家都用过SharedPreferences来保存用户的某些settings值.Shared Preferences 以键值对的形式存储私有的原生类型数据,这里的私有的是指只对你自己的app可见的,也就是说别的app是无法访问到的. 客户端代码为了使用它有2种方式,一种是通过Context#getSharedPreferences(String prefName, int mode)方法, 另一种是Activity自己的getPreferences(int mo

Android源码分析之Builder模式

http://www.w3c.com.cn/android%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8Bbuilder%E6%A8%A1%E5%BC%8F Android源码分析之Builder模式

Android源码分析之模板方法模式

模式的定义 定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 使用场景 1.多个子类有公有的方法,并且逻辑基本相同时. 2.重要.复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现. 3.重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为. UML类图 角色介绍 AbstractClass : 抽象类,定义了一套算法框架. ConcreteClass1 :

Android源码分析--system_server进程分析

在上一篇博文中我们进行了有关Zygote进程的分析,我们知道Zygote进程创建了一个重要的进程–system_server进程后就进入了无限循环中,之后Android系统中的重要任务就交给了system_server进程,作为zygote的嫡长子进程,system_server进程的意义非凡,今天我们来分析一下system_server进程. 创建system_server进程 在ZygoteInit中main方法中,通过调用startSystemServer方法开启了system_serve