- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
3.2、核心方法
1、execute() 方法
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); /** AsyncTask 类的 execute 方法**/ public final AsyncTask<Params, Progress, Result> execute(Params... params) { //调用 executeOnExecutor 方法 return executeOnExecutor(sDefaultExecutor, params); }
当执行 execute 方法时,实际上是调用了 executeOnExecutor 方法。这里传递了两个参数,一个是 sDefaultExecutor,一个是 params。从上面的源码可以看出,sDefaultExecutor 其实是一个 SerialExecutor 对象,实现了串行线程队列。params 其实最终会赋给 doInBackground 方法去处理。
2、executeOnExecutor() 方法
//exec 执行 AsyncTask.execute() 方法时传递进来的参数 sDefaultExecutor,这个 sDefaultExecutor 其实就是 SerialExecutor 对象。默认是串行执行的 //若想变成并发执行 exec 可以传入 AsyncTask.THREAD_POOL_EXECUTOR。 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { //如果一个任务已经进入执行的状态,再执行就会抛异常。这就决定了一个 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)"); } } //一旦 executeOnExecutor 调用了就标记为运行状态 mStatus = Status.RUNNING; //实际是调用子类里面的 onPreExecute onPreExecute(); //将处理的参数类型赋值给 mWorker mWorker.mParams = params; //execute 是调用 SERIAL_EXECUTOR 的 execute,mFuture 就是之前 AsyncTask 构造初始化赋值的 FutureTask。 exec.execute(mFuture); return this; }
这里要说明一下,AsyncTask 的异步任务有三种状态
- PENDING 待执行状态。当 AsyncTask 被创建时,就进入了 PENDING 状态。
- RUNNING 运行状态。当调用 executeOnExecutor,就进入了 RUNNING 状态。
- FINISHED 结束状态。当 AsyncTask 完成(用户 cancel() 或任务执行完毕) 时,就进入了 FINISHED 状态。
3、SerialExecutor 的 execute 方法
private static class SerialExecutor implements Executor { //循环数组实现的双向 Queue。大小是 2 的倍数,默认是 16。有队头队尾两个下标 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); //当前正在运行的 runnable Runnable mActive; public synchronized void execute(final Runnable r) { //添加到双端队列里面去 mTasks.offer(new Runnable() { public void run() { try { //执行的是 mFuture 就是之前 AsyncTask 构造初始化赋值的 FutureTask 的 run() 方法 r.run(); } finally { //无论执行结果如何都会取出下一个任务执行 scheduleNext(); } } }); //如果没有活动的 runnable,从双端队列里面取出一个 runnable 放到线程池中运行 //第一个请求任务过来的时候 mActive 是空的 if (mActive == null) { //取出下一个任务来执行 scheduleNext(); } } protected synchronized void scheduleNext() { //从双端队列中取出一个任务 if ((mActive = mTasks.poll()) != null) { //线程池执行取出来的任务,真正执行任务的 THREAD_POOL_EXECUTOR.execute(mActive); } } }//java
exec.execute(mFuture)
执行时,SerialExecutor 将 FutureTask 作为参数执行 execute 方法。在 execute 方法中,假设 FutureTask 插入进了两个以上的任务队列到 mTasks 中,第一次过来 mActive==null
,通过 mTasks.poll()
取出一个任务丢给线程池运行,线程池执行 r.run,其实就是执行 FutureTask 的 run 方法,因为传递进来的 r 参数就是 mFuture。等到上一个线程执完 r.run() 完之后,这里是通过一个 try-finally 代码块,并在 finally 中调用了 scheduleNext() 方法,保证无论发生什么情况,scheduleNext() 都会取出下一个任务执行。
接着因为 mActive 不为空了,不会再执行``scheduleNext()`,由于存在一个循环队列,每个 Runnable 被执行的时候,都进入去队列,然后在执行完后出队,才会进入下一个 Runnable 的执行流程。由此可知道这是一个串行的执行过程,同一时刻只会有一个线程正在执行,其余的均处于等待状态。
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams);//调用子类的 doInBackground Binder.flushPendingCommands(); return postResult(result);//执行完后通过 postResult 结果传递出去 } };
上文中提到调用 call()
的流程: SerialExecutor.execute() -> FutureTask.run() -> WorkerRunnable.call()
如果回调了 call()
方法,就会调用了 doInBackground(mParams)
方法,这都是在子线程中执行的。执行完后,将结果通过 postResult(result)
发送出去。
4、AsyncTask 的 postResult 方法
private Result postResult(Result result) { @SuppressWarnings("unchecked") //获取一个 handler,等到一个消息,将结果封装在 Message Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result));//new AsyncTaskResult<Result>(this, result) 将得到的结果再做了一层封装 //将消息发送到主线程,会回调 handleMessage() 方法 message.sendToTarget(); return result; }
因为 postResult(Result result)
还是在子线程中调用的,如果要发送给主线程,必须通过 Handler。源码中使用 sHandler 并带着 MESSAGE_POST_RESULT 和封装了任务执行结果的对象 AsyncTaskResult,然后 message.sendToTarget() 开始发消息。
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { //初始化一个 InternalHandler,用与将结果发送给主线程 sHandler = new InternalHandler(); } return sHandler; } }
并在 InternalHandler 的 handleMessage 中开始处理消息,InternalHandler 的源码如下所示:
private static class InternalHandler extends Handler { public InternalHandler() { // 这个 handler 是关联到主线程的 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; } } }
- 这里根据消息的类型进行了判断,如果是 MESSAGE_POST_RESULT 消息,就会去执行 finish() 方法,
finish()
源码如下文所示:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
如果任务已经取消了,调用 onCancelled
方法,如果没被取消,则调用 onPostExecute() 方法。
- 如果
doInBackground(Void... params)
调用publishProgress()
方法,实际就是发送一条 MESSAGE_POST_PROGRESS 消息,就会去执行 onProgressUpdate() 方法。publishProgress()
的源码如下文所示:
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
如果你还不够清晰,请看下面的这个流程图。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论