【源码】康一康过时的→AsyncTask(上)

简介: AsyncTask 对很多老Android来说,是一个很有年代感的东西了,想当年毕业找工作,AsyncTask可是面试必问。随着 EventBus、RxJava、Kotlin协程 等的出现,它渐渐淡出了我们的视野,面试八股文也少了它的身影,很多新晋的Android开发估计都没听过它。不禁感叹:技术更新迭代真快,学不动了!面试不问,但一些老旧项目中还有用到它,接盘维护难免要学下,索性花一丢丢时间过一下:废弃原因 + 核心原理 + 演进历史。

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


网络异常,图片无法展示
|


看完定义,看实现:


网络异常,图片无法展示
|


相关文章
|
7月前
|
测试技术
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
详解单元测试问题之MockHandlerImpl类的handle方法中VerificationMode不为空如何解决
83 3
|
6月前
|
存储 安全 iOS开发
iOS 16 系统键盘修复问题之确定UIKeyboardTaskQueue类中对_lock的使用是否正确如何解决
iOS 16 系统键盘修复问题之确定UIKeyboardTaskQueue类中对_lock的使用是否正确如何解决
|
安全 Java 应用服务中间件
通过JDK源码分析关闭钩子详解
通过JDK源码分析关闭钩子详解
通过JDK源码分析关闭钩子详解
|
Java 调度 Android开发
【源码】康一康过时的→AsyncTask(中)
AsyncTask 对很多老Android来说,是一个很有年代感的东西了,想当年毕业找工作,AsyncTask可是面试必问。 随着 EventBus、RxJava、Kotlin协程 等的出现,它渐渐淡出了我们的视野,面试八股文也少了它的身影,很多新晋的Android开发估计都没听过它。不禁感叹:技术更新迭代真快,学不动了!面试不问,但一些老旧项目中还有用到它,接盘维护难免要学下,索性花一丢丢时间过一下:废弃原因 + 核心原理 + 演进历史。
169 0
|
存储 Android开发 iOS开发
Appium自动化(13) - 详解 Keyboard 类里的方法和源码分析
Appium自动化(13) - 详解 Keyboard 类里的方法和源码分析
340 0
Appium自动化(13) - 详解 Keyboard 类里的方法和源码分析
Drools 6.4.0Final版本KieScanner内存泄漏Bug
Drools 6.4.0Final版本KieScanner内存泄漏Bug
359 0
Drools 6.4.0Final版本KieScanner内存泄漏Bug
|
Java Android开发 Kotlin
【源码】康一康过时的→AsyncTask(下)
AsyncTask 对很多老Android来说,是一个很有年代感的东西了,想当年毕业找工作,AsyncTask可是面试必问。 随着 EventBus、RxJava、Kotlin协程 等的出现,它渐渐淡出了我们的视野,面试八股文也少了它的身影,很多新晋的Android开发估计都没听过它。不禁感叹:技术更新迭代真快,学不动了!面试不问,但一些老旧项目中还有用到它,接盘维护难免要学下,索性花一丢丢时间过一下:废弃原因 + 核心原理 + 演进历史。
199 0
|
NoSQL 关系型数据库 MySQL
Runnable 在浏览器里发现、分享、修改、编译、运行代码片段
对于大部分开发者而言,搜索代码片段是他们的日常。问题在于这些代码片段分布在整个网络上。来自亚马逊的几位程序员无法忍受这样的麻烦,于是创立了代码片段一站式服务平台Runnable,他们把它称作“代码界的Youtube”。在Runnable上,用户不但可以找到代码片段,而且还可以修改乃至运行这些代码片段。
146 0
Runnable 在浏览器里发现、分享、修改、编译、运行代码片段
|
Android开发
Eclipse重写toString()出现错误,求怎么解决?
我的Ecplise的版本:  Eclipse使用快捷键重写toString()时出现错误,如下所示: 其实是Java9和eclipse有bug冲突,但是不知道,怎么解决?先自己手写吧,以后解决了,再分享!  我的GitHub地址:https://github.
1200 0
visual studio编写C#代码时“未能从程序集.....中加载类型”和“找不到方法”的一种可能的解决办法
编译前报错:$exception    {"未能从程序集“XSW.MySQLDAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中加载类型“XSW.MySQLDAL.EnterpriseLibraryProductDAL”。
1766 0