用于长时间运行的Android AsyncTask

引用在这里find的AsyncTask的文档,它说

理想情况下,AsyncTasks应该用于短操作(最多几秒钟)。如果需要保持线程长时间运行,强烈build议您使用java.util.concurrent pacakge提供的各种API,例如执行器,ThreadPoolExecutor和FutureTask。

现在我的问题出现了,为什么? doInBackground函数运行在UI线程之外。 那么在这里长时间的运行会有什么危害呢?

这是一个非常好的问题,作为一个Android程序员需要时间来充分理解这个问题。 的确AsyncTask有两个相关的主要问题:

  • 他们与活动生命周期关系不大
  • 他们很容易造成内存泄漏。

在RoboSpice Motivations应用程序( 在Google Play上可用 )中,我们详细回答了这个问题。 它将深入了解AsyncTasks,Loaders及其function和缺点,并向您介绍networking请求的替代解决scheme:RoboSpice。 networking请求是Android中的常见要求,本质上是长时间运行的操作。 这是从应用程序摘录:

AsyncTask和Activity生命周期

AsyncTasks不遵循Activity实例的生命周期。 如果你在一个Activity里面启动了一个AsyncTask,并且你旋转了这个设备,这个Activity将被销毁,并且一个新的实例将被创build。 但是AsyncTask不会死。 它会继续活着直到完成。

完成后,AsyncTask将不会更新新Activity的UI。 事实上,它更新了以前不再显示的活动实例。 这可能会导致types为java.lang.IllegalArgumentException的exception:如果您使用findViewById来检索Activity中的视图,则视图不会附加到窗口pipe理器。

内存泄漏问题

创buildAsyncTasks作为活动的内部类是非常方便的。 由于AsyncTask需要在任务完成或正在进行时操作Activity的视图,因此使用Activity的内部类似乎很方便:内部类可以直接访问外部类的任何字段。

尽pipe如此,这意味着内部类将在其外部类实例上持有一个无形的参考:活动。

从长远来看,这会产生一个内存泄漏:如果AsyncTask持续了很长时间,它会使活动保持“活跃”,而Android则希望摆脱它,因为它不能再显示。 该活动不能被垃圾收集,这是Android保存设备资源的中心机制。


对于长时间运行的操作,使用AsyncTasks确实是一个非常糟糕的主意。 尽pipe如此,对于短暂的生活,比如在1到2秒之后更新一个View,这些都是不错的select。

我鼓励你下载RoboSpice Motivations应用程序 ,它真正解释了这一点,并提供了一些后台操作的不同方式的示例和演示。

为什么?

因为默认情况下, AsyncTask使用了一个你没有创build的线程池。 不要把没有创build的池中的资源绑定在一起,因为你不知道池的要求是什么。 如果该池的文档告诉您不要这样做,则不要将池中的资源捆绑在一起。

特别是,从Android 3.2开始, AsyncTask默认使用的线程池(对于android:targetSdkVersion设置为13或更高的应用程序)只有一个线程 – 如果你无限期地绑定了这个线程,你的其他任务会跑。

Aysnc任务是专门的线程,仍然意味着与您的应用程序GUI使用,但同时保持UI线程资源繁重的任务。 所以当更新列表,更改视图等需要你做一些读取操作或更新操作时,你应该使用asynchronous任务,这样你可以保持这些操作离开UI线程,但是请注意,这些操作仍然以某种方式连接到UI 。

对于不需要UI更新的长时间运行的任务,您可以使用服务,因为即使没有UI,也可以使用服务。

所以对于短的任务,使用asynchronous任务,因为他们可以在你的产卵活动结束后被操作系统杀死(通常不会中途操作,但会完成任务)。 而对于长期和重复的任务,请使用服务。

欲了解更多信息,请参阅主题:

AsyncTask超过几秒钟?

即使活动已经被破坏,AsyncTask也不会停止