0x1、Deprecated 原因
AsyncTask,Android(API 3) 引入,一个轻量级的异步任务库,允许以 非线程堵塞 的方式执行操作。经过了好几个版本的调整,比如:
- Android 1.6前,串行执行,原理:一个子线程进行任务的串行执行;
- Android 1.6到2.3,并行执行,原理:一个线程数为5的线程池并行执行,但如果前五个任务执行时间过长,会堵塞后续任务执行,故不适合大量任务并发执行;
- Android 3.0后,串行执行,原理:全局线程池进行串行处理任务;
还有一些小调整,比如Android 10后,线程池核心数变成1,线程队列从BlockingQueue变成SynchronousQueue等。
真够折腾的,打开 AsyncTask的官方文档 一行橙字映入眼帘:
网络异常,图片无法展示
|
AsyncTask类在 Android 11(API 30) 中被废弃了,推荐使用java.util.concurrent或Kotlin协程来替代。
em...就废弃了啊,往下看是废弃原因的解释:
网络异常,图片无法展示
|
大概意思:
- AsyncTask本意是使得UI线程的使用变得简单正确,但最常见的用法是集成到UI中,反而导致了 Context泄露、忘记回调、configuration变化Crash 问题。
- 不同版本AsyncTask的兼容问题;
- 吞掉了来自doInBackground的异常;
- 不能提供比直接使用Executor更多的功能;
- Thread和Handler的辅助类,并非线程框架,主要用于执行一些时间不太长的异步任务;
- 用法复杂,三个通用参数(Params、Progress、Result) + 四个回调方法;
简单概括下:版本兼容、功能少、用起来还麻烦。
0x2、AsyncTask 用法详解
Talk is cheap,show you the Code,了解完过时原因,接着温习下它的用法:
// 继承AsyncTask抽象类,建议声明为Activity的静态内部类,避免context泄露 // 泛型参数依次为: // // Params → 开始异步任务时传入的参数类型 → execute(Params) // Progress → 异步任务执行过程,返回进度值 // Result → 异步任务执行完成后,返回结果类型 → doInBackground() // class MyAsyncTask: AsyncTask<Task, Int, String>() { // 必须重写!在此执行耗时操作,返回执行结果 override fun doInBackground(vararg params: Task?): String { return "执行耗时操作" } // 执行线程任务前的回调,即执行execute()前自动调用,常用作界面初始化操作 override fun onPreExecute() { } // 在主线程中显示任务执行的进度,自动调用啊,按需重写 override fun onProgressUpdate(vararg values: Int?) { } // 接受线程任务执行结果,线程任务结束时自动调用,可在此将结果更新到UI组件 override fun onPostExecute(result: String?) { } // 异步任务被取消时自动调用,用于将异步任务设为取消状态,需在doInBackground()中停止 // 此方法调用onPostExecute就不会被调用 override fun onCancelled() {} } // 在主线程中初始化自定义AsyncTask实例后,调用execute(XXX) // 每个AsyncTask实例只能调用一次execute(),多次调用会抛出异常 // 注①:Activity重建(如屏幕旋转),之前持有的Activity引用已失效,任务正常运行, // 但任务执行完成后,在onPostExecute中修改UI不会生效,建议在Activity恢复的相关方法 // 中重启AsyncTask任务; // 注②:最好在Activity、Fragment的onDestory()中调用AsyncTask.cancle()将AsyncTask设置 // 为canceled状态,然后在doInBackground中去判断这个AsyncTask的status是否为: // AsyncTask.Status.RUNNING,是,直接返回,结束任务 }
em...用法看着也不算太复杂 (不和rx、协程等对比的话),接着以Android 9.0源码为例,讲解一波核心原理~
0x3、核心原理讲解
① 单个任务的流转
跟 execute()
→ executeOnExecutor()
:
网络异常,图片无法展示
|
AsyncTask内部定义了一个状态字段 mStatus
,可选值有:PENDING(挂起)、RUNNING(运行中)、FINISHED(结束)。
从上述代码也可以看出为何**不能重复调用AsyncTask实例的execute()**方法,接着看下工作线程 → mWorker
:
网络异常,图片无法展示
|
看完定义,看实现:
网络异常,图片无法展示
|