引用此处找到的 AsyncTask 的文档,它说:
AsyncTasks 最好用于短时间的操作(最多几秒钟)。如果您需要保持线程长时间运行,强烈建议您使用 java.util.concurrent 包提供的各种 API,例如Executor、ThreadPoolExecutor 和 FutureTask。
现在我的问题出现了:为什么?该doInBackground()
函数在 UI 线程之外运行,那么在这里长时间运行操作有什么危害?
引用此处找到的 AsyncTask 的文档,它说:
AsyncTasks 最好用于短时间的操作(最多几秒钟)。如果您需要保持线程长时间运行,强烈建议您使用 java.util.concurrent 包提供的各种 API,例如Executor、ThreadPoolExecutor 和 FutureTask。
现在我的问题出现了:为什么?该doInBackground()
函数在 UI 线程之外运行,那么在这里长时间运行操作有什么危害?
这是一个非常好的问题,作为一个 Android 程序员需要时间来完全理解这个问题。事实上 AsyncTask 有两个相关的主要问题:
在RoboSpice Motivations 应用程序(可在 Google Play 上获得)中,我们详细回答了这个问题。它将深入了解 AsyncTasks、Loaders、它们的特性和缺点,并向您介绍网络请求的替代解决方案:RoboSpice。网络请求是 Android 中的常见需求,本质上是长时间运行的操作。这是该应用程序的摘录:
AsyncTasks 不遵循 Activity 实例的生命周期。如果您在 Activity 中启动 AsyncTask 并旋转设备,则 Activity 将被销毁并创建一个新实例。但是 AsyncTask 不会死。它将继续存在,直到完成。
当它完成时,AsyncTask 不会更新新 Activity 的 UI。实际上,它会更新不再显示的活动的前一个实例。这可能会导致 java.lang.IllegalArgumentException: View not attach to window manager 类型的异常,例如,如果您使用 findViewById 来检索 Activity 中的视图。
将 AsyncTasks 创建为活动的内部类非常方便。由于 AsyncTask 需要在任务完成或正在进行时操作 Activity 的视图,因此使用 Activity 的内部类似乎很方便:内部类可以直接访问外部类的任何字段。
然而,这意味着内部类将在其外部类实例上持有一个不可见的引用:Activity。
从长远来看,这会产生内存泄漏:如果 AsyncTask 持续很长时间,它会保持活动“活动”,而 Android 想要摆脱它,因为它不再显示。Activity 不能被垃圾收集,这是 Android 在设备上保留资源的中心机制。
将 AsyncTasks 用于长时间运行的操作确实是一个非常非常糟糕的主意。不过,它们适用于短暂的生命周期,例如在 1 或 2 秒后更新视图。
我鼓励您下载RoboSpice Motivations 应用程序,它确实深入地解释了这一点,并提供了执行某些后台操作的不同方法的示例和演示。
为什么 ?
因为AsyncTask
,默认情况下,使用您没有创建的线程池。永远不要占用不是您创建的池中的资源,因为您不知道该池的要求是什么。如果该池的文档告诉您不要占用您未创建的池中的资源,则永远不要占用该池中的资源,就像这里的情况一样。
特别是,从 Android 3.2 开始,AsyncTask
默认使用的线程池(对于android:targetSdkVersion
设置为 13 或更高版本的应用程序)只有一个线程——如果你无限期地占用这个线程,你的其他任务都不会运行。
Aysnc 任务是专门的线程,仍然可以与您的应用程序 GUI 一起使用,但同时保持 UI 线程的资源繁重任务。因此,当更新列表、更改视图等需要您执行一些获取操作或更新操作时,您应该使用异步任务,以便您可以将这些操作保持在 UI 线程之外,但请注意这些操作仍以某种方式连接到 UI .
对于不需要更新 UI 的长时间运行的任务,您可以改用服务,因为即使没有 UI,它们也可以生存。
因此,对于短任务,请使用异步任务,因为它们可能会在您的生成活动终止后被操作系统杀死(通常不会在操作过程中终止,但会完成其任务)。对于冗长且重复的任务,请改用服务。
有关更多信息,请参阅线程:
和