AsyncTask 完全解析
AsyncTask 完全解析
引言
我们知道,在 Android 中,UI 线程不能执行耗时操作;在子线程中不能执行更新 UI 的操作。如果需要在子线程中进行 UI 相关的操作,那么就需要借助 Android 中的异步消息机制(比如我们熟悉的Handler消息机制)才能完成。如果我们自己写代码来进行相关的处理,不仅麻烦,而且大部分的代码都是相同的,AsyncTask 的出现就能帮我们省去大部分的代码,并且可以非常灵活方便地从子线程切换到UI线程。今天就从 AsyncTask 的简单使用到源码进行解析,一步一步看看他是怎么实现的。
AsyncTask 的简单使用
创建 AsyncTask 实现类
class DownLoadAsyncTask extends AsyncTask { @Override protected Boolean doInBackground(String... params) { // 运行在子线程,执行访异步任务 Log.i("DownLoadAsyncTask", "doInBackground(): 开始执行异步任务"); // publishProgress(Integer); // 调用更新进度方法 return downLoadImage(params[0]); // 下载图片方法 } @Override protected void onPreExecute() { // 运行在主线程,异步任务执行前的准备工作 Log.i("DownLoadAsyncTask", "onPreExecute(): 执行异步任务前的准备工作"); super.onPreExecute(); } @Override protected void onPostExecute(Boolean result) { // 运行在主线程,异步任务执行完成之后的回调 Log.i("DownLoadAsyncTask", "onPostExecute(): 异步任务执行完成之后的回调 => " + result); super.onPostExecute(result); } @Override protected void onProgressUpdate(Integer... progresses) { // 运行在主线程,用于更新进度 // 注意:该方法需要在doInBackground()内部调用publishProgress()方法并传递进度,否则不会执行 Log.i("DownLoadAsyncTask", "onProgressUpdate(): 用于更新进度"); super.onProgressUpdate(progresses); }}
AsyncTask
源码解析
构造方法
public AsyncTask() { this((Looper) null);}public AsyncTask(@Nullable Handler handler) { this(handler != null ? handler.getLooper() : null);}/** * @hide */public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; mFuture = new FutureTask(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); } } };}
构造方法说明:
- 最终调用的都是
AsyncTask(@Nullable Looper callbackLooper)
方法,但是这个方法使用了@hide
注解,开发者并不能直接调用。构造方法虽然比较长,但是他并没有任何的操作被执行,只是初始化了mHandler
、mWorker
、mFuture
几个变量,并且将mWorker
对象作为mFuture
的构造方法参数传递给了mFuture
对象。 mHandler
是MainHandler- 有一点需要注意:构造方法只能在UI线程中调用
构造方法中用到的部分对象说明:
- mHandler:Android Handler消息机制中的Handler对象,这里是
InternalHandler
对象,暂时记住就行了,后面会粘贴出具体实现的代码和说明
class InternalHandler extends Handler:
- mWorker:实现
Callable
接口的AsyncTask
类的内部类WorkerRunnable
- mFuture:
FutureTask
对象。FutureTask
对象的继承关系
1. class FutureTask implements RunnableFuture
2. interface RunnableFuture extends Runnable, Future
执行异步任务方法
public final AsyncTask execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);// 调用内部方法}public final AsyncTask executeOnExecutor(Executor exec, Params... params) { 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; // 将状态设置为RUNNING onPreExecute(); // 回调异步任务执行前的准备工作方法 mWorker.mParams = params; // 将传递的参数赋值给 mWorker 对象的 mParams 字段 exec.execute(mFuture); // 执行 mFuture return this;}
到这一步的时候,我们的任务已经切换子线程中了。
方法说明:
- 判断当前的状态,如果是
RUNNING
或者是FINISHED
就抛出异常 - 执行回调方法
onPreExecute()
,执行异步任务前的准备工作,比如显示进度对话框等 - 将
mFuture
对象 交给exec.execute(mFuture)
执行
exec.execute(mFuture)说明:
exec:即 sDefaultExecutor
;实现 Executor
接口的内部类 SerialExecutor
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static class SerialExecutor implements Executor { final ArrayDeque mTasks = new ArrayDeque(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); // 调用参数 Runnable 对象的 run() 方法 } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } }}
通过上面 SerialExecutor
类的定义,我们可以看到 execute()
方法调用了它的参数(即mFuture
)的run()
方法,我们继续查看mFuture
的 run()
方法
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { Callable c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { runner = null; int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}
在该方法中主要是调用了 callable
对象的 call()
方法,我们一起看看 callable
对象是从哪里来的。
public FutureTask(Callable callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable}
查看 FutureTask
对象的构造方法,我们发现callable
对象是在构造方法中初始化的。好,我们现在就只要知道 FutureTask
对象是在哪里初始化的,就知道 call()
方法的具体执行内容是什么了。那么你是否还记得我们在查看 AsyncTask
类的构造方法时看到了它初始化几个变量就有FutureTask
对象,所以在这里执行的 call()
方法具体的方法体就是在AsyncTask
类的构造方法总中定义的方法体。为了方便观察,我把这段代码在粘贴一次:
mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); // 执行 doInBackground 回调方法,参数在mParams的值在executeOnExecutor()中初始化了 Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); // 设置结果 } return result; } };
看了这么久的代码,我们总算看到了执行任务的方法,也就是我们的重写方法 doInBackground(mParams)
返回的 Result
是结果泛型类型(第三个泛型的类型),在上面说过了三个泛型表示的意义;也就是说,到了这一步,我们的异步任务真正的开始执行了;我们接着看finally
中的代码,调用的 postResult(result)
方法,看看这个方法的具体实现:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result;}
在这个方法中使用了一个新的类 AsyncTaskResult
,它也是 AsyncTask
的内部类,定义如下:
private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; }}
回过头在看 postResult(Result result)
这个方法中的代码非常简单,getHandler()
方法获取到我们在构造方法中初始化的 mHandler
对象,接着获取一个 Message
对象并且创建一个 AsyncTaskResult
对象(这个对象包含了AsyncTask
类的本类对象和 doInBackground()
方法返回的结果对象2个参数)作为消息的内容,最后将这个消息发送到目标 mHandler
。上面说过了这个mHandler
是InternalHandler
,但是没有贴出具体实现的代码,那么现在我们就来看一下它到底做了些什么(InternalHandler
类是AsyncTask
类的内部类):
private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @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; } }}
这段代码我想大家都能看懂吧,最常见的 Handler
写法,通过判断 Message
的 what
进行不同的操作(任务执行完成或者更新进度)。我们只需要弄清楚 result.mTask
表示的哪一个对象就可以知道调用的方法是什么了。
在postResult(Result result)
方法中,我们知道了 Message
的 obj
字段的值是 AsyncTaskResult
对象,参数是 this
和 doInBackground()
方法返回的结果对象,很容易知道this
表示 AsyncTask
本类对象;在通过 AsyncTaskResult
的构造方法我就知道 result.mTask
就是AsyncTask
的本类对象,所以我们就知道了 result.mTask.finish(result.mData[0])
方法就是AsyncTask
类的 finish(Result result)
方法了;同理result.mTask.onProgressUpdate(result.mData)
方法就是AsyncTask
类的 onProgressUpdate(Progress... values)
方法。
看看AsyncTask
类的 finish(Result result)
方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED;}
方法说明:
- 判断是不是取消了,如果取消了,就回调
onCancelled()
方法(开发者重写) - 如果没有取消就回调
onPostExecute(Result result)
方法(开发者重写) - 将任务的执行状态改变为
FINISHED
到此为止,我们发现的任务执行前的准备方法onPreExecute()
、任务执行方法 doInBackground
以及 取消方法 onCancelled()
和完成方法 onPostExecute()
都成功回调了;但是我们更新进度的方法 onProgressUpdate()
却并没有在哪里有调用;如果看的比较知仔细的可能已经发现了,我在第一部分简单使用中说明了:
那么我们看看 publishProgress(Progress... values)
方法:
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
它和 postResult(Result result)
方法是一样的,发送一个消息,就不在多说了,回过头看一下就知道了。
以上就是 AsyncTask
的主要执行过程。
相关文章
《Android 中的 HandlerThread 类详解》
《Android 中的 IntentService 类详解》
《Android中的Handler机制分析(一) Handler和Message分析》
《Android中的Handler机制分析(二) MessageQueue分析》
《Android中的Handler机制分析(三) Looper分析和Handler其他知识》
更多相关文章
- Android(安卓)Handler解析
- Android-使用HttpURLConnection实现多线程下载
- Android(安卓)通过listView+RadioButton实现列表的单选功能
- Android通知栏-Notification(通知消息)
- Unity和Android相互通信
- 美团热修复 Robust 方案接入(一)
- Android中的属性动画理解
- Android基础知识(2)—事件处理
- android data binding