天天看点

Android AsyncTask 使用时需要注意的地方

使用 AsyncTask 可以方便的实现分线程执行耗时任务,完成后更新 UI 这个需求,但是由于 AsyncTask 的自身特点,有以下几个地方需要注意:

  • 兼容老版本时 AsyncTask 执行顺序的问题
  • 内存泄露风险
  • 与 Activity 生命周期不相同

执行顺序问题

在 Android 1.6 到 2.3.2 中,AsyncTask的执行顺序修改为并行执行。如果同时执行多个任务,则这些任务会并行执行。 当任务访问同一个资源的时候 会出现并发问题。

而在 Android 3.0 以后的版本中,AsyncTask 又修改为了顺序执行,并且新添加了一个函数 executeOnExecutor(Executor),如果您需要并行执行,则只需要调用该函数,并把参数设置为并行执行即可。

参数如下:

* Executors.newCachedThreadPool()。即创建一个单独的线程池。

* AsyncTask.THREAD_POOL_EXECUTOR。使用现有的线程池,并发执行

* AsyncTask.SERIAL_EXECUTOR。效果和 execute() 一样。

内存泄露风险

在 Activity 中,将 AsyncTask 作为内部类时, 这个类会隐式的引用这个 Activity 。当这个 task 的 run 没有执行完时,这个 Activity 就不会被销毁。

与 Activity 生命周期不相同

当 Activity 结束的时候,如果 AsyncTask 没有执行完成,它会以它自有的方式继续运行,即使你退出了整个应用程序。AsyncTask提前结束的唯一方法是通过调用AsyncTask.cancel()进行取消。

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

AsyncTask 和 Activity 容易引起的另外一个问题是屏幕旋转时引起的异常。如果你在一个 Activity 中创建了一个 AsyncTask,你旋转了屏幕,这个 Activity 将会被销毁并且会重新创建一个新的实例。但是 AsyncTask 没有销毁,它将会继续执行直到完成。当它执行完成后,它实际上是更新了上一个已经不存在的 Activity,如果你原本想在 onPostExecute() 中更新 UI 的话,这时的 AsyncTask 将不会更新新的 Activity,并且这个操作会引发一个异常:java.lang.IllegalArgumentException。

如果你是想要在 onPostExecute() 中关闭一个 dialog,则会发生:java.lang.IllegalArgumentException: View not attached to window manager(前提是你忘记在Activity的onStop()中忘记dismiss)。不仅如此,还会在show()的调用出抛出一个 lead window的异常

AsyncTask 隐藏的陷阱

Android App 内存泄露之Thread