译文:Android中糟糕的AsyncTask

NOV 8TH, 2014

AsyncTask是一个很常用的API,尤其异步处理数据并将数据应用到视图的操作场合。其实AsyncTask并不是那么好,甚至有些糟糕。本文我会讲AsyncTask会引起哪些问题,如何修复这些问题,并且关于AsyncTask的一些替代方案。

AsyncTask

从Android API 3(1.5 Cupcake)开始,AsyncTask被引入用来帮助开发者更简单地管理线程。实际上在Android 1.0和1.1也是有类似的实现,那就是UserTask。UserTask和AsyncTask有着相同的API及实现,但是由于由于1.0和1.1的设备份额微乎其微,这里的概念就不会涉及到UserTask。

生命周期

关于AsyncTask存在一个这样广泛的误解,很多人认为一个在Activity中的AsyncTask会随着Activity的销毁而销毁。然后事实并非如此。AsyncTask会一直执行doInBackground()方法直到方法执行结束。一旦上述方法结束,会依据情况进行不同的操作。

  • 如果cancel(boolean)调用了,则执行onCancelled(Result)方法
  • 如果cancel(boolean)没有调用,则执行onPostExecute(Result)方法

AsyncTask的cancel方法需要一个布尔值的参数,参数名为mayInterruptIfRunning,意思是如果正在执行是否可以打断,如果这个值设置为true,表示这个任务可以被打断,否则,正在执行的程序会继续执行直到完成。如果在doInBackground()方法中有一个循环操作,我们应该在循环中使用isCancelled()来判断,如果返回为true,我们应该避免执行后续无用的循环操作。

总之,我们使用AsyncTask需要确保AsyncTask正确地取消。

不好好工作的cancel()

简而言之的答案,有时候起作用。

如果你调用了AsyncTask的cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用onPostExecute()方法。但是实际上这是让应用程序执行了没有意义的操作。那么是不是我们调用cancel(true)前面的问题就能解决呢?并非如此。如果mayInterruptIfRunning设置为true,会使任务尽早结束,但是如果的doInBackground()有不可打断的方法会失效,比如这个BitmapFactory.decodeStream() IO操作。但是你可以提前关闭IO流并捕获这样操作抛出的异常。但是这样会使得cancel()方法没有任何意义。

内存泄露

还有一种常见的情况就是,在Activity中使用非静态匿名内部AsyncTask类,由于Java内部类的特点,AsyncTask内部类会持有外部类的隐式引用。详细请参考细话Java:”失效”的private修饰符,由于AsyncTask的生命周期可能比Activity的长,当Activity进行销毁AsyncTask还在执行时,由于AsyncTask持有Activity的引用,导致Activity对象无法回收,进而产生内存泄露。

结果丢失

另一个问题就是在屏幕旋转等造成Activity重新创建时AsyncTask数据丢失的问题。当Activity销毁并创新创建后,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。

串行还是并行

关于AsyncTask时串行还是并行有很多疑问,这很正常,因为它经过多次的修改。如果你并不明白什么时串行还是并行,可以通过接下来的例子了解,假设我们在一个方法体里面有如下两行代码

1
2
new AsyncTask1().execute();
new AsyncTask2().execute();

上面的两个任务时同时执行呢,还是AsyncTask1执行结束之后,AsyncTask2才能执行呢?实际上是结果依据API不同而不同。

在1.6(Donut)之前:

在第一版的AsyncTask,任务是串行调度。一个任务执行完成另一个才能执行。由于串行执行任务,使用多个AsyncTask可能会带来有些问题。所以这并不是一个很好的处理异步(尤其是需要将结果作用于UI试图)操作的方法。

从1.6到2.3(Gingerbread)

后来Android团队决定让AsyncTask并行来解决1.6之前引起的问题,这个问题是解决了,新的问题又出现了。很多开发者实际上依赖于顺序执行的行为。于是很多并发的问题蜂拥而至。

3.0(Honeycomb)到现在

好吧,开发者可能并不喜欢让AsyncTask并行,于是Android团队又把AsyncTask改成了串行。当然这一次的修改并没有完全禁止AsyncTask并行。你可以通过设置executeOnExecutor(Executor)来实现多个AsyncTask并行。关于API文档的描述如下

If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel:

1
2
3
4
5
6
7
8
public static void execute(AsyncTask as) {  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) {      as.execute();
  } else {      as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
}
//(This code does not work for API lvl 1 to 3)

真的需要AsyncTask么

并非如此,使用AsyncTask虽然可以以简短的代码实现异步操作,但是正如本文提到的,你需要让AsyncTask正常工作的话,需要注意很多条条框框。推荐的一种进行异步操作的技术就是使用Loaders。这个方法从Android 3.0 (Honeycomb)开始引入,在android支持包中也有包含。可以通过查看官方的文档来详细了解Loaders。

本次译文对原文有少部分删减修改处理。

引用推荐

  • 原文地址(墙外的 Orz)
  • Grepcode AsyncTsk 源码参考
  • 另一篇介绍AsyncTask陷阱的文章
  • 罗升阳的Android系统源代码情景分析

译文:Android中糟糕的AsyncTask之停止AsyncTask操作相关推荐

  1. android中一种不支持的lua操作

    今天写了一段lua代码,在win32中正常运行,在android中运行无效. 大概是这样的: ------file1.lua----- local t = {} t.str = "this ...

  2. Android中从源码分析关于AsyncTask的使用

    Android在框架层提供了异步任务类,AysncTask,用于执行后台任务,并将执行结果更新到UI线程.为什么要用异步任务呢?这是因为如果某个任务太耗时间的话,会阻塞UI主线程,而我们知道UI线程如 ...

  3. Android中监听ScrollView滑动停止和滑动到底部

    1.监听ScrollView滑动停止: [java] view plaincopy /********************监听ScrollView滑动停止********************* ...

  4. 安卓增删改查用sql语句号码_详解Android中一些SQLite的增删改查操作

    在Android开发中经常要涉及到对数据的操作.Android本身提供了四种数据存储方式.包括:SharePreference,SQLite,Content Provider,File. 在Andro ...

  5. Android中HTTPS之一(三)具体操作(代码实现)

    一.背景 前两篇对Http和Https的原理进行了介绍,接下来是在Android代码中如何具体配置:同时再强调说明一下如果使用权威ca机构申请(购买)的证书客户端也要进行验证. 二.涉及的点 2.1 ...

  6. AndroidStudio_android中实现对properties文件的读写操作_不把properties文件放在assets文件夹中_支持读写---Android原生开发工作笔记238

    这个东西还挺麻烦,因为是android中,我们一般把文件放到assets文件夹中去,但是实际上,这个raw文件夹和assets文件夹 是只读的,对,就是只读的只能读取,不能写入,所以一定要把文件写入到 ...

  7. 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

    文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...

  8. Android中 AsyncTask

    Android AsyncTask 在程序处理中必然会遇上耗时的操作,如访问网络,下载数据,访问数据库等,如何存在耗时的操作 又不能影响界面显示交互. 在某些耗时可以控制的情况下,我们可以分批操作,对 ...

  9. android 中使用AsyncTask实现简单的异步编程

    在开发移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验.但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI ...

最新文章

  1. ASP.NET AJAX学习记要(2)-下手之DOM
  2. 宝塔控制面板创建ftp后链接不上的解决方法
  3. 路飞学城-python爬虫密训-第三章
  4. bugzilla dbd-mysql_别人写的关于在Windows下安装BugZilla的说明,不错,值得借鉴
  5. 华岗(1977-),男,博士,宁波市智慧城市规划标准发展研究院副研究员。
  6. java is instance of_详谈Java中instanceof和isInstance的区别
  7. vSAN 设计、部署、运维最佳实践 | 资料
  8. SQL Server数据库技术大全——08讲 PD的使用
  9. #20165201 macOS中统计代码总行数
  10. teamcity mysql 配置_TeamCity
  11. ros清华源_ROS操作系统学习(一)ROS安装
  12. 大名鼎鼎的挖掘鸡最新版本6.5
  13. 最全的Excel-sumif函数多条件求和案例汇总
  14. 【算法】硬币找钱问题(贪心算法)
  15. 薛之谦明星人物介绍html源码 html期末大作业 课程设计
  16. Order By 排序
  17. 【干货分享】IOS非越狱渠道运营必知的10条
  18. POJ-3255 Roadblocks
  19. 关于写好这个“简历”的几点思考
  20. Mac环境下利用Python解锁ViVo BL锁

热门文章

  1. 怎样用计算机打出分数,分数怎么打出来
  2. Edsger Dijkstra经典言论 (ZT)
  3. 防盗充电语音警报——让手机充电更安全
  4. Maven:工程的拆分与聚合
  5. C/C++ 函数(求一元二次方程的根)
  6. 教MM们拍照摆POSE
  7. SPOJ 5971 lcm sum
  8. 标点符号也能过关 部分网游防沉迷形同虚设
  9. python❀运算符号作业
  10. 蓝牙耳机什么牌子性价比高一些?综合性能强的蓝牙耳机推荐