smilevchy's blog

Life & Study & Chasing

Interrogation of AsyncTask

当需要进行一项耗时久的任务时(下载文件、访问网络等),一般都知道必须在 worker thread 中进行。但是在现实场景中不可能单纯新建一个线程那么简单,大部分时候需要和 main thread 进行交互、或者说还要保证任务能够成功进行,不会遇到被销毁的情况。可是,单纯的 thread 并不具备这些能力。

那怎么办呢?

以上说的场景交互在 Android 开发中形成了一种 pattern,而 Android 团队就把这种 pattern 提取成了一个工具类出来给开发者使用,即 AsyncTask。

关于 AsyncTask 的使用方法可参见官方文档

一般情况下,AsyncTask 的确就是那么容易使用。但在某些情况下,你会发现这个类出问题了。

这个是因为 AsyncTask 的本质缺陷导致。

Android 的基本组件 Activity/Receiver/Service 本身具有一定的生命周期管理(Life Circle Management),而 AsyncTask 并不具备与之对应的生命周期管理。

假设一个场景如下,你编写了一个 AsyncTask,然后在一个 Activity 里调用该 AsyncTask,并且把自身引用传递进去,为了后续的一些函数调用。大部分情况下是没有问题,但是当设备转换屏幕方向时,Android 系统会销毁这个 Activity 再重建一个新的,此时之前传进去 AsyncTask 里的引用已经“无效”了,因为它指向了一个被销毁的 Activity,你再也不可能对其做任何 UI 操作,甚至会抛出 NullPointerException。即是说,你需要注意传进给 AsyncTask 的任何具有生命周期管理的引用,下一秒这个引用可能就失效了。

解决方法?

对于此类具有生命周期管理的引用统一使用 WeakReference,当引用指向的对象被系统销毁时,可以让这些对象被 GC 处理,同时在使用到引用的代码处再判断是否非空来决定怎么处理。

此外,当外部发生生命周期状态改变时(按返回键、Home键、取消进度框等),若对应的 AsyncTask 需要做相应的反应时(取消任务进行、继续任务进行等),还需要监听外部的生命周期状态改变事件。

总之,AsyncTask 看起来很简单,但需要在实际场景中考虑是否可能会出现问题。

android

« Call function lazily Reaction to Effective Java »