为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第6天 异步消息框架 Asynctask 源码解读

标签:
Android

课程名称BAT大牛亲授技能+技巧 Android面试快速充电升级
课程章节:Android基础相关面试问题
主讲老师DocMike

课程内容

1.为什么要引入 AsyncTask?

通常情况下,Android 的 app 运行都至少有一个进程。一个进程可以有多个线程,在这些线程中,有一个线程是 UI 线程(MainThread),UI 线程之外的称为工作线程(Worker Thread)。MainThread 主要负责控制 UI 页面的显示、更新和交互,所以 UI 线程不能够执行耗时操作,会直接影响用户体验,所以网络请求,数据库操作,复杂的逻辑运行等都要在单独的线程中完成,这样就可以避免阻塞 UI 线程。同时也要避免因为频繁的创建和销毁线程,带来的资源消耗。

AsyncTask 是 Android 封装的一个轻量级的异步消息框架,它内部的实现机制主要是对 Handler 和线程池的封装,做到了既能够执行后台任务,还能避免不必要的系统开销。

2.AsyncTask 的主要回调方法

  1. onPreExecute(),这个方法会在后台任务开始执行前调用,在主线程执行。用于进行初始化操作。

  2. doInBackground(),这个方法在子线程中执行,负责处理耗时操作。

  3. 如果要更新UI,可以通过调用 publishProgress() 方法来完成比如反馈当前的进度。

  4. onProgressUpdate(),当调用 publishProgress()方法后,这个方法就会被调用,方法中携带的参数就是后台任务中传递过来的。在这个方法运行在主线程,可以对 UI 进行更新操作。

  5. onPostExecute(),这个方法运行在主线程中,当 doInBackground() 执行完毕,并通过 return 语句进行返回时,这个方法就会被调用。

2.AsyncTask 的组成

  1. InternalHandler,是 AsyncTask 中的一个静态类, 它是一个绑定了主线程的 Handler 的子类,AsyncTask 正是通过这个 Handler,实现了线程的切换。这也是为什么 AsyncTask 的实例必须要在主线程中创建,因为只有这样,InternalHandler 初始化时才能默认绑定 MainLooper。

  2. 线程池,AsyncTask 内部封装了 SerialExecutor 和 THREAD_POOL_EXECUTOR 两个线程池,SerialExecutor 线程池用于任务的排队,让需要执行的多个耗时任务按顺序排列。THREAD_POOL_EXECUTOR 线程池才真正执行任务。默认情况下 AsyncTask 是按照串行的方式执行任务的,这是因为 SerialExecutor 是按照串行的方式提取任务的。

  3. FutureTask,AsyncTask 之所以能有返回值,正是因为有执行 Runnable 的 FutureTask。Future 实现了 Runnable 和 Callable 接口,Runnable 的run() 方法是无返回值的,Callable 的 call() 方法是有一个 V 泛型的返回值,FutureTask 的 get() 方法会以阻塞等待的方式等待 Callable 的 call() 方法的返回值。

3.梳理 AsyncTask 的执行过程

  1. 在 UI 线程创建 AsyncTask 实例,通过调用 execute() 方法启动任务,默认情况下 AsyncTask 是按照顺序执行的,执行过程中线程的切换是通过 Handler 的子类 InternalHandler 实现的,InternalHandler 创建时自动绑定 MainLooper ,所以 InternalHandler 对 Message 的处理运行在 UI 线程。

  2. 创建 AsyncTask 实例时,会创建 WorkerRunnable 对象和 FutureTask 对象,在线程池中的线程运行时会在 FutureTask 的 run() 方法中调用 WorkerRunnable 的 call() 方法,call() 方法就运行在了子线程,call() 方法中调用 doInBackground 方法也就运行在子线程。

  3. doInBackground() 方法执行结束之后会通过 InternalHandler 发消息将当前 AsyncTask 的返回值传递到主线程。

  4. 主线程处理消息时调用对应 AsyncTask 的 finish() 方法,通过 onCanclelled() 和 onPostExecute() 方法处理任务取消和任务执行完成两种情况。

  5. 子线程运行过程中的进度,也是通过类似的方式,在 doInBackground() 中调用 publishProgress() 方法,该方法会将进度通过 InternalHandler 发消息,主线程收到 InternalHandler 发来的进度之后,通过 onProgressUpdata() 接收进度。

4.使用 AsyncTask 注意事项

  1. AsyncTask 的实例必须在 UI 线程中创建。

  2. execute() 方法必须在 UI 线程中调用。

  3. 不要手动调用 onPreExecute(),doInBackground(),onProgressUpdate(),onPostExecute() 这几个方法,这些是 AsyncTask 自动调用的。

  4. 一个 AsyncTask 实例只能执行一次 execute() 方法,执行多次会抛出异常。

课程收获

这一章重点梳理了 AsyncTask 在使用过程中的一些注意事项,通过对源码的分析,明白了这些注意事项的底层机制,做到了知其然并知其所以然。

图片描述

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
12
获赞与收藏
17

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消