AsyncTask源码解析
来源:互联网 发布:mac 重新安装jenkins 编辑:程序博客网 时间:2024/05/22 11:44
AsyncTask类是Android设计的一个执行异步方法的类,我们可以利用这个类执行一些耗时的任务,然后根据结果更新UI,在执行任务时,也可以更新UI,如设置进度条的进度等等。今天,我们从源码分析这个类,学习执行异步方法的思想,这对我写异步框架应该会起到帮助。Show me the code !!
从属性开始,我分为2部分:(1)线程池的初始化。(2)普通属性。
(1)线程池的初始化
直接看代码:
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 workprivate 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()); }};// 任务队列,当线程池的工作线程大于核心线程CORE_POOL_SIZE,新的任务便会加入到这个任务队列中,这里定义队列大小为128private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);// 真正执行任务的线程池public static final Executor THREAD_POOL_EXECUTOR;// 静态块static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, // 核心线程数 MAXIMUM_POOL_SIZE, // 最大线程数 KEEP_ALIVE_SECONDS, // 非核心线程闲置的时间 TimeUnit.SECONDS, // KEEP_ALIVE_SECONDS的单位 sPoolWorkQueue, // 任务队列 sThreadFactory); // 线程工厂 // 设置核心线程闲置时,超过KEEP_ALIVE_SECONDS也被销毁,这里是1秒 threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor;}
在静态块中,一开始便初始化了一个线程池。更多关于线程池,请参考我上一篇博文Android线程池浅析。
(2)普通属性
// 这个是加入任务的线程池,接下来会分析public static final Executor SERIAL_EXECUTOR = new SerialExecutor();// Handler处理消息的标志private static final int MESSAGE_POST_RESULT = 0x1;private static final int MESSAGE_POST_PROGRESS = 0x2;// 默认执行任务的线程池,定义为SerialExecutor,待会分析private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static InternalHandler sHandler;// 异步任务,待会分析private final WorkerRunnable<Params, Result> mWorker;private final FutureTask<Result> mFuture;// 状态private volatile Status mStatus = Status.PENDING;// 原子性布尔变量,用于判断是否取消和执行的标志private final AtomicBoolean mCancelled = new AtomicBoolean();private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
普通属性我们简单的分析了一下,上面提到SerialExecutor线程池,我们来看看代码:
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { // 将Runnable任务加入到mTasks队列中 mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); // 如果没有任务在执行,就开始执行任务 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { // 从mTasks队列取出任务,并加入到THREAD_POOL_EXECUTOR线程池执行任务 if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }}
从代码可以看出,SerialExecutor是临时保存任务的,真正执行任务的是THREAD_POOL_EXECUTOR线程池。从代码还看出,AsyncTask是串行执行的,这点很重要。还涉及到队列的小知识,如果mTasks没有元素Runnable的话,调用mTasks.poll()会返回null,不会阻塞。
属性中还定义了状态,有以下3种:
public enum Status { /** * Indicates that the task has not been executed yet. */ PENDING, /** * Indicates that the task is running. */ RUNNING, /** * Indicates that {@link AsyncTask#onPostExecute} has finished. */ FINISHED,}
好了,属性部分到这里已经看完了,我们看看构造函数吧:
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { ... } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { ... } };}
构造函数主要初始化mFuture,里面的实现代码再分析。为什么要使用FutureTask呢?那是因为AsyncTask任务需要可取消的功能,而FutureTask正好满足需求。关于FutureTask我也写了一篇博文,请参考FutureTask源码浅析。
我们要执行AsyncTask时,要调用它的execute,代码如下:
@MainThreadpublic final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);}
@MainThread表示要在主线程执行,至于为什么,待会我一一道来。我们继续跟踪executeOnExecutor方法:
@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { // 如果当前状态不是Status.PENDING,直接报错。 // 这就表明了,一个AsyncTask只能执行一次。 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,这个方法是钩子方法,子类可以选择重写 onPreExecute(); // 把我们传入的参数交给mWorker mWorker.mParams = params; // 开始执行mFuture任务 exec.execute(mFuture); return this;}
我们先来看看mWorker。它是一个WorkerRunnable,实现Callable接口,如果你知道FutureTask,应该知道为什么要实现Callable。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { // 定义了参数,AsyncTask就是用过这个属性,把参数传进来使用的 Params[] mParams;}
调用exec.execute(mFuture)便开始执行任务,上面已经分析过了,其实是先加入一个队列,然后交给THREAD_POOL_EXECUTOR线程池开启线程执行。
我们看看mFuture执行任务的代码,那么得回到初始化mFuture的代码了,也就是构造函数:
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { // 设置这个任务已经在执行了 mTaskInvoked.set(true); // 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // noinspection unchecked // 这里开始执行我们子类重写的doInBackground方法 Result result = doInBackground(mParams); Binder.flushPendingCommands(); // 调用postResult方法,里面主要是调用 return postResult(result); }};mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { // 任务执行完毕后执行 try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } }};
如果你对FutureTask熟悉的话,应该知道,FutureTask执行任务会先调用Callable的call方法。上面的代码中,mWorker会先执行call方法,然后mFuture的done方法才会调用。mWorker的call方法中,先调用了我们子类重写的doInBackground方法,然后调用了postResult方法。我们看看postResult方法的代码:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result;}
从代码可以知道,postResult就是把任务执行的结果通过Handler(消息机制)传到主线程。如果对消息机制不了的,可以看我写的3篇关于消息机制的博文Android消息机制(1)- 简介。getHandler得到的是主线程的Handler,代码如下:
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; }}
我们再来看看自定义的InternalHandler代码:
private static class InternalHandler extends Handler { public InternalHandler() { // 主线程Looper super(Looper.getMainLooper()); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } }}
看InternalHandler重写的handleMessage方法,主要处理2个消息事件:MESSAGE_POST_RESULT和MESSAGE_POST_PROGRESS。postResult方法传过来的是MESSAGE_POST_RESULT事件,这里涉及到一个类,AsyncTaskResult,代码:
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; }}
其实就是一个保存数据和AsyncTask的包装类。
我们回到InternalHandler处理MESSAGE_POST_RESULT事件,调用了result.mTask.finish,从AsyncTaskResult看出,其实也就是执行AsyncTask的finish方法,代码如下:
private void finish(Result result) { if (isCancelled()) { // 如果任务取消了,调用onCancelled方法 onCancelled(result); } else { // 如果任务没有取消,调用onPostExecute方法 onPostExecute(result); } // 更新状态 mStatus = Status.FINISHED;}
finish方法代码很简单,不用多说。InternalHandler还可以处理一个事件,MESSAGE_POST_PROGRESS,作用是在执行doInBackground方法时,还能通过调用publishProgress方法更新UI。
我们先看看publishProgress方法:
@WorkerThreadprotected final void publishProgress(Progress... values) { if (!isCancelled()) { // 如果任务没有取消,分发消息给InternalHandler处理 getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); }}
主要是分发消息给InternalHandler处理,InternalHandler调用result.mTask.onProgressUpdate(result.mData)方法处理事件,也就是交给AsyncTask的onProgressUpdate方法处理。而onProgressUpdate是一个挂钩方法,交给子类去实现。
接下来给出子类可以重写和必须重写的方法,主要是看一下:
// 子类必须重写,执行异步的方法@WorkerThreadprotected abstract Result doInBackground(Params... params);// 其他方法子类可以选择重写,挂钩方法@MainThreadprotected void onPreExecute() {}@SuppressWarnings({"UnusedDeclaration"})@MainThreadprotected void onPostExecute(Result result) {}@SuppressWarnings({"UnusedDeclaration"})@MainThreadprotected void onProgressUpdate(Progress... values) {}@SuppressWarnings({"UnusedParameters"})@MainThreadprotected void onCancelled(Result result) { onCancelled();} @MainThreadprotected void onCancelled() {}
到这里,相信你对AsyncTask的机制已经很熟悉了。还有一个,AsyncTask是可取消的,我们看看取消的代码:
public final boolean cancel(boolean mayInterruptIfRunning) { // 设置取消标志 mCancelled.set(true); // 调用FutureTask的取消方法 return mFuture.cancel(mayInterruptIfRunning);}// 判断是否取消public final boolean isCancelled() { return mCancelled.get();}
FutureTask调用cancel方法传入了一个参数,通过解读FutureTask源码可知,如果参数mayInterruptIfRunning为true的话,会立刻中断线程,并设置Interrupt标志。如果为false,则会继续等待线程执行完,设置Cancel标志。
我还在想AsyncTask的cancel方法为什么没有调用onCancelled方法呢,原来我之前对中断线程有误解,正好这里更正了我对线程中断的理解。我原以为调用Thread的interrupt()方法,run方法就不会继续往下执行,直接跳出run方法,这种想法完全是错误的。其实调用Thread的interrupt()方法,如果Thread处于阻塞状态,如处于sleep或者wait,此时,Thread就会收到中断的信号,提前终止阻塞状态,同时抛出InterruptedException异常,然后继续往下执行。如果Thread并没有阻塞,调用Thread的interrupt()方法并不会起效果,run方法还是会继续执行下去。为了证明这点,我特意写了个demo,代码:
public class MainActivity extends Activity { // 阻塞队列 private LinkedBlockingQueue<Integer> queue; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); queue = new LinkedBlockingQueue<>(); final Thread thread = new Thread(new Runnable() { @Override public void run() { int result; try { // 从队列取出元素 result = queue.take(); } catch (InterruptedException e) { // 处理Interrupted异常 e.printStackTrace(); result = -1; } Log.e(getClass().getName(), "结果为" + result); sayHello(); } }); thread.start(); // 2秒后调用thread.interrupt方法 new Handler().postDelayed(new Runnable() { @Override public void run() { thread.interrupt(); } }, 2000); } private void sayHello() { Log.e(getClass().getName(), "hello, i executed ----------- "); }}
打印的结果如下:
从打印结果可以知道,sayHello方法还是会执行的,证明我刚才对Thread.interrupt()方法的理解是正确的。
我们再来看调用AsyncTask的cancel(true)方法(因为false不会中断任务线程),我们结合mFuture初始化代码看:
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { // 设置这个任务已经在执行了 mTaskInvoked.set(true); // 设置线程优先级,处于THREAD_PRIORITY_BACKGROUND Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // noinspection unchecked // 这里开始执行我们子类重写的doInBackground方法 Result result = doInBackground(mParams); Binder.flushPendingCommands(); // 调用postResult方法,里面主要是调用 return postResult(result); }};mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { // 任务执行完毕后执行 try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } }};
因为doInBackground是异步方法,一般在这里阻塞,调用FutureTask的cancel方法后,doInBackground提前结束阻塞,继续往下执行,那么postResult方法也会被执行,接着调用finish方法:
private void finish(Result result) { if (isCancelled()) { // 如果任务取消了,调用onCancelled方法 onCancelled(result); } else { // 如果任务没有取消,调用onPostExecute方法 onPostExecute(result); } // 更新状态 mStatus = Status.FINISHED;}
此时isCancelled为true,所以onCancelled会被执行。这里有学到了关于线程中断的一点小知识,太激动了!!!
到此,整个AsyncTask的原理分析的差不多了,其实我们也能利用这种思想做出我们自己异步框架。我们不是重新做轮子,我们的目标是做更好的轮子。浏览了一下源码,还有个地方你应该知道:
public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec;}
其实我们可以自定义AsyncTask执行任务的线程池和任务排序,默认是顺序执行,如果你想要任务按照你想要的顺序排序,可以自定义Executor,代码回忆一下:
...public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }}...
如果你并不想要重新定义顺序,只想自定义线程池,执行方法时,调用executeOnExecutor,以下是execute和executeOnExecutor的区别:
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);}public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { ...}
AsyncTask源码到这里分析已经结束了,发现自己的好好补补线程和队列的知识。
AsyncTask源码下载地址
AsyncTask源码
参考资料
JAVA线程的interrupt
- AsyncTask源码解析
- AsyncTask源码解析
- Android AsyncTask源码解析
- AsyncTask源码解析
- AsyncTask源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- Android AsyncTask 源码解析
- AsyncTask源码解析
- Android AsyncTask 源码解析
- AsyncTask源码解析
- AsyncTask源码解析
- Android AsyncTask 源码解析
- Android:AsyncTask源码解析
- Android AsyncTask源码解析
- AsyncTask源码解析
- AsyncTask源码解析
- 00-Thrift简介(官方文档略读)
- Java UML
- 浮动元素自动居中显示
- ubuntu 配置ckermit nfs tftpd-hpa ssh vim ftp wine virtualbox JDK ctags cscope
- jira 6.3.6 破解
- AsyncTask源码解析
- Linux CentOS 7 下 JDK 安装与配置
- SSM框架——详细整合教程
- Anaconda+tensorflow1.0安装
- 树形动规初步:“选课”讲解
- FAT12文件系统结构探究
- 爬虫算法之PageRank
- Java设计模式之装饰者模式
- Java学习笔记(二)