AsyncTask的工作原理
AsyncTask的工作原理
概述
- AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UL从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。
- AsyncTask是一个抽象的泛型类,它提供了Params、Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务的执行进度的类型,而Result则表示后台任务的返回结果的类型,如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替。
- onPreExecute(),在主线程中执行,在异步任务执行之前,此方法会被调用,一般可以用于做一些准备工作。
- doInBackground(Params…params),在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute方法。另外,publishProgress还要判断下载任务是否被外界取消了。
- onProgressUpdate(Progress…values),在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
- onPostExecute(Result result),在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数是后台任务的返回值,即doInBackground的返回值。
- onPreExecute先执行,接着是doInBackground,最后才是onPostExecute。除了上述四个方法以外,AsyncTask还提供了onCancelled()方法,它同样在主线程中执行,当异步任务被取消时,onCancelled()方法会被调用,这个时候onPostExecute则不会被调用。
- AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程,当然这个过程在Android4.1及以上版本中己经被系统自动完成。
- AsyncTask的对象必须在主线程中创建。
- execute方法必须在UI线程调用。
- 不要在程序中直接调用onPreExecute、onPostExecute、doInBackground和onProgressUpdate方法。
- 一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常。
- 在Android1.6之前,AsyncTask是串行执行任务的,Android1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又釆用一个线程来串行执行任务。尽管如此,在Android3.0以及后续的版本中,我们仍然可以通过AsyncTask的executeOnExecutor方法来并行地执行任务。
- 首先,execute方法会被调用,execute方法又会调用executeOnExecutor方法。
文章图片
文章图片
- 在上面的代码中,sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程池开始执行。
文章图片
- 从SerialExecutor的实现可以分析AsyncTask的排队执行的过程。首先系统会把AsyncTask的Params参数封装为FutureTask对象,FutureTask是一个并发类,在这里它充当了Runnable的作用。接着这个FutureTask会交给SerialExecutor的execute方法去处理,SerialExecutor的execute方法首先会把FutureTask对象插入到任务队列mTasks中,如果这个时候没有正在活动的AsyncTask任务,那么就会调用SerialExecutor的scheduleNext方法来执行下一个AsyncTask任务。同时当一个AsyncTask任务执行完后,AsyncTask会继续执行其他任务直到所有的任务都被执行为止,从这一点可以看出,在默认情况下,AsyncTask是串行执行的。
- AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正地执行任务,InternalHandler用于将执行环境从线程池切换到主线程。在AsyncTask的构造方法中有如下这么一段代码,由于FutureTask的run方法会调用mWorker的call方法,因此mWorker的call方法最终会在线程池中执行。
文章图片
- 在mWorker的call方法中,首先将mTaskInvoked设为true,表示当前任务已经被调用过了,然后执行AsyncTask的doInBackground方法,接着将其返回值传递给postResult方法,它的实现如下所示。
文章图片
文章图片
- 在上面的代码中,postResult方法会通过sHandler发送一个MESSAGE_POST_RESULT的消息,这个sHandler的定义如下所示。
文章图片
- 可以发现,sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程中创建。由于静态成员会在加载类的时候进行初始化,因此这就变相要求AsyncTask的类必须在主线程中加载,否则同一个进程中的AsyncTask都将无法正常工作。sHandler收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法。AsyncTask的finish方法的逻辑比较简单,如果AsyncTask被取消执行了,那么就调用onCancelled方法,否则就会调用onPostExecute方法,可以看到doInBackground的返回结果会传递给onPostExecute方法。
文章图片
文章图片
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量