用于长时间运行的Android AsyncTask

时间:2012-10-09 10:02:55

标签: android android-asynctask

引用了here的AsyncTask文档,它说

  

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

现在我的问题出现了? doInBackground函数在UI线程下运行。那么在这里长期运行会有什么危害呢?

4 个答案:

答案 0 :(得分:117)

这是一个非常好的问题,需要时间作为Android程序员才能完全理解这个问题。实际上,AsyncTask有两个相关的主要问题:

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

RoboSpice动机应用(available on Google Play)内,我们会详细回答这个问题。它将深入介绍AsyncTasks,Loaders,它们的功能和缺点,并向您介绍网络请求的替代解决方案:RoboSpice。 网络请求是Android中的常见要求,本质上是长期运行的操作 。 以下是应用程序的摘录:

AsyncTask和Activity生命周期

AsyncTasks不遵循Activity实例的生命周期。如果在Activity中启动AsyncTask并旋转设备,则将销毁Activity并创建新实例。但AsyncTask不会死。它会继续生存直到它完成。

完成后,AsyncTask将不会更新新Activity的UI。实际上,它更新了之前的活动实例 不再显示。这可能导致java.lang.IllegalArgumentException类型的异常:如果你没有附加到窗口管理器的视图 例如,使用findViewById来检索Activity内的视图。

内存泄漏问题

将AsyncTasks创建为活动的内部类非常方便。因为AsyncTask需要操纵视图 当Activity完成或正在进行时,使用Activity的内部类似乎很方便:内部类可以 直接访问外部类的任何字段。

然而,这意味着内部类将在其外部类实例上保存一个不可见的引用:Activity。

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


将AsyncTasks用于长时间运行操作真的是一个非常糟糕的主意。然而,它们适用于短期生活,例如在1或2秒后更新视图。

我鼓励您下载RoboSpice Motivations app,它确实深入地解释了这一点,并提供了进行某些后台操作的不同方法的示例和演示。

答案 1 :(得分:38)

  

为什么?

因为默认情况下AsyncTask使用您未创建的线程池 。永远不要从未创建的池中占用资源,因为您不知道该池的要求是什么。如果该池的文档告诉您不要,那么永远不要从您未创建的池中占用资源,就像这里的情况一样。

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

答案 2 :(得分:4)

Aysnc任务是专门的线程,仍然可以与您的应用程序GUI一起使用,但同时保持UI线程的资源繁重的任务。因此,当更新列表,更改视图等内容需要您执行一些获取操作或更新操作时,您应该使用异步任务,以便您可以将这些操作保留在UI线程之外,但请注意这些操作仍以某种方式连接到UI

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

因此,对于简短任务,请使用异步任务,因为它们可能会在您的产生活动消失后被操作系统杀死(通常不会在操作中死亡但将完成其任务)。对于漫长而重复的任务,请改用服务。

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

AsyncTask for longer than a few seconds?

AsyncTask won't stop even when the activity has destroyed

答案 3 :(得分:1)

AsyncTask的问题在于,如果将其定义为活动的非静态内部类,则它将引用活动。在异步任务的容器完成活动,但AsyncTask中的后台工作继续的情况下,活动对象不会被垃圾收集,因为有对它的引用,这会导致内存泄漏。

解决此问题的解决方案是定义活动的async task as static inner class并使用对上下文的弱引用。

但是,将它用于简单快速的后台任务是个好主意。要使用干净的代码开发应用程序,最好使用RxJava来运行复杂的后台任务并使用结果更新UI。