AsyncTask隐藏的陷阱

当AsyncTask被介绍到Android中时,它被贴上“无忧线程”的标签。其目标是让与UI线程交互的后台线程变得更容易。从这一点上讲它是成功的,但并非绝对安全————有很多AsyncTask无法应对的情况。如果不小心处理,不会考虑到AsyncTask出错的情况,很容易盲目使用AsyncTask。下面是一些未充分理解AsyncTask会遇到的问题:

AsyncTask与(屏幕)旋转

AsyncTask的起初目标是为了简化与UI线程进行交互的后台线程的实现。因此多数使用场景是用一个AsyncTask去运行一个耗时的操作,完成之后去更新UI部分(在AsyncTask.onPostExecute()中实现)。

当你旋转屏幕,你会发现这种做法是相当...。当一个App旋转时,整个Activity会被销毁和重建。当Activity重启时,AsyncTask中对该Activity的引用是无效的,因此onPostExecute()就不会起作用。如果使用AsyncTask作为Activity的内部类,AsyncTask会隐式引用了当前Activity,就会出现上述情况,这会使你非常疑惑。

这个问题的通常做法是对AsyncTask持有一个引用,在配置更改,随着Activity重启更新目标Activity。有多种方式可以实现,要么使用一个全局性的持有者(如Application对象),或者通过Activity.onRetainNonConfigurationInstance().传递一个对象。对于基于Fragment的系统,可以使用保留的Fragment(通过Fragment.setRetainedInstance(true)获取)去存储正在运行的AsyncTasks。

AsyncTasks与生命周期

与上面的提到一样:认为生成AsyncTask的Activity终止了,AsyncTask也会终止,这其实是一个误解。它会以它自有的方式继续运行,即使你退出了整个应用程序。AsyncTask提前结束的唯一方法是通过调用AsyncTask.cancel()进行取消。

这表明你必须亲自管理 AsyncTask的取消操作;否则,由于不必要的后台线程会导致app阻塞的风险,或者内存泄露。当不再需要一个AsyncTask时,一定要取消它,防止在app执行期间引起任何问题。

取消AsyncTasks

假设你有一个运行与AsyncTask中的搜索查询。在AsyncTask运行时,用户也许会改变搜索参数,因此你要调用AsyncTask.cancel(),并且为接下来的查询启动一个新的AsyncTask。这似乎合乎逻辑...检查日志后会发现所有的AsyncTask都会完整执行,不论你是否调用了cancel()方法。

传递mayInterruptIfRunning(cancel()方法的参数名)为true都会发生这种情况—————回事?

出现这种情况是因为误解了AsyncTask.cancel()的实际执行效果。AsyncTask不会不考虑结果而直接结束一个线程。调用cancel()其实是给AsyncTask设置一个"canceled"状态。这取决于你去检查AsyncTask是否已经取消,之后决定是否终止你的操作。对于mayInterruptIfRunning——它所作的只是向运行中的线程发出interrupt()调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程。

多数情况下,有两个简单的方法可供选择:在长期运行的操作中定期检查AsyncTask.isCancelled()的调用;或者使线程中断。不论哪种方法,当你调用AsyncTask.cancelled()时,这些方法应该阻止你的操作继续运行。

这个建议并非总是有效————要是调用一个长期运行切不可中断的方法(如 BitmapFactory.decodeStream())会怎么样呢?成功的案例是创建一个引起异常抛出的场景(过早地关闭BitmapFactory使用的流)。这说明cancel()调用并不能解决这个问题————需要外部介入。

在当前AsyncTasks中的限制

我不提倡在后台启动数百个线程;并且,在可启动AsyncTasks的数量上做出限制将毫无用处。最新版的AsyncTask限制使用128个并发线程,另外还有10个在阻塞队列中。因此在队列任务完成之前,如果队列中的task多于138个就会引起app崩溃。使用AsyncTasks从网络加载位图(Bitmap)就会出现这样的问题。

如果想突破这些限制,应该重新思考对后台线程调用的设计。一个可选方案:对tasks设置一个更智能化的队列,这样不必一次性全部启动它们。要是情况紧急,可以拷贝AsyncTask的副本并在代码中调整线程池的大小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荣华富贵8

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值