用于长时间运行的 Android AsyncTask
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12797550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android AsyncTask for long running operations
提问by user1730789
Quoting the documentation for AsyncTask found here, it says:
引用此处找到的 AsyncTask 文档,它说:
AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.
理想情况下,AsyncTasks 应该用于短期操作(最多几秒钟)。如果您需要让线程长时间运行,强烈建议您使用 java.util.concurrent pacakge 提供的各种 API,例如Executor、ThreadPoolExecutor 和 FutureTask。
Now my question arises: why? The doInBackground()
function runs off the UI thread so what harm is there by having a long running operation here?
现在我的问题出现了:为什么?该doInBackground()
函数在 UI 线程之外运行,那么在这里长时间运行操作有什么危害?
回答by Snicolas
It is a very good question, it takes time as an Android Programmer to fully understand the issue. Indeed AsyncTask have two main issues that are related :
这是一个很好的问题,作为一个 Android 程序员需要时间来完全理解这个问题。事实上,AsyncTask 有两个相关的主要问题:
- They are poorly tied to the activity life cycle
- They create memory leaks very easily.
- 它们与活动生命周期的联系很差
- 它们很容易造成内存泄漏。
Inside the RoboSpiceMotivations app (available on Google Play) we answer that question in detail. It will give an in-depth view of AsyncTasks, Loaders, their features and drawbacks and also introduce you to an alternative solution for network requests : RoboSpice. Network requests are a common requirement in Android and are by nature long running operations . Here is an excerpt from the app :
在RoboSpiceMotivations 应用程序(在 Google Play 上可用)中,我们详细回答了这个问题。它将深入了解 AsyncTasks、Loaders、它们的特性和缺点,并向您介绍网络请求的替代解决方案:RoboSpice。网络请求是 Android 中的常见要求,并且本质上是长时间运行的操作。以下是该应用程序的摘录:
The AsyncTask and Activity life cycle
AsyncTask 和 Activity 生命周期
AsyncTasks don't follow Activity instances' life cycle. If you start an AsyncTask inside an Activity and you rotate the device, the Activity will be destroyed and a new instance will be created. But the AsyncTask will not die. It will go on living until it completes.
AsyncTask 不遵循 Activity 实例的生命周期。如果您在 Activity 中启动 AsyncTask 并旋转设备,则 Activity 将被销毁并创建一个新实例。但是 AsyncTask 不会死。它将继续存在,直到完成。
And when it completes, the AsyncTask won't update the UI of the new Activity. Indeed it updates the former instance of the activity that is not displayed anymore. This can lead to an Exception of the type java.lang.IllegalArgumentException: View not attached to window manager if you use, for instance, findViewById to retrieve a view inside the Activity.
当它完成时,AsyncTask 不会更新新 Activity 的 UI。事实上,它更新了不再显示的活动的前一个实例。这可能会导致 java.lang.IllegalArgumentException: View not attach to window manager 类型的异常,例如,如果您使用 findViewById 来检索 Activity 内的视图。
Memory leak issue
内存泄漏问题
It is very convenient to create AsyncTasks as inner classes of your Activities. As the AsyncTask will need to manipulate the views of the Activity when the task is complete or in progress, using an inner class of the Activity seems convenient : inner classes can access directly any field of the outer class.
创建 AsyncTasks 作为活动的内部类非常方便。由于 AsyncTask 在任务完成或正在进行时需要操作 Activity 的视图,因此使用 Activity 的内部类似乎很方便:内部类可以直接访问外部类的任何字段。
Nevertheless, it means the inner class will hold an invisible reference on its outer class instance : the Activity.
尽管如此,这意味着内部类将在其外部类实例上持有一个不可见的引用:Activity。
On the long run, this produces a memory leak : if the AsyncTask lasts for long, it keeps the activity "alive" whereas Android would like to get rid of it as it can no longer be displayed. The activity can't be garbage collected and that's a central mechanism for Android to preserve resources on the device.
从长远来看,这会导致内存泄漏:如果 AsyncTask 持续很长时间,它会保持活动“活着”,而 Android 则希望摆脱它,因为它无法再显示。活动不能被垃圾收集,这是 Android 保留设备资源的中心机制。
It is really a very very bad idea to use AsyncTasks for long running operations. Nevertheless, they are fine for short living ones such as updating a View after 1 or 2 seconds.
将 AsyncTasks 用于长时间运行的操作确实是一个非常非常糟糕的主意。然而,它们适用于短暂的生命周期,例如在 1 或 2 秒后更新视图。
I encourage you to download the RoboSpice Motivations app, it really explains this in-depth and provides samples and demonstrations of the different ways to do some background operations.
我鼓励您下载RoboSpice Motivations 应用程序,它确实深入解释了这一点,并提供了执行某些后台操作的不同方法的示例和演示。
回答by CommonsWare
why ?
为什么 ?
Because AsyncTask
, by default, uses a thread pool that you did not create. Never tie up resources from a pool that you did not create, as you do not know what that pool's requirements are. And never tie up resources from a pool that you did not create if the documentation for that pool tells you not to, as is the case here.
因为AsyncTask
,默认情况下,使用您未创建的线程池。切勿从非您创建的池中占用资源,因为您不知道该池的要求是什么。如果池的文档告诉您不要从您未创建的池中占用资源,则永远不要占用资源,就像这里的情况一样。
In particular, starting with Android 3.2, the thread pool used by AsyncTask
by default (for apps with android:targetSdkVersion
set to 13 or higher) has only onethread in it -- if you tie up this thread indefinitely, none of your other tasks will run.
特别是,从 Android 3.2 开始,AsyncTask
默认使用的线程池(对于android:targetSdkVersion
设置为 13 或更高版本的应用程序)只有一个线程——如果你无限期地占用这个线程,你的其他任务将不会运行。
回答by Anup Cowkur
Aysnc task are specialized threads that are still meant to be used with your apps GUI but whilst keeping resource-heavy tasks of the UI thread. So when stuff like updating lists, changing your views etc require you to do some fetch operations or update operations, you should use async tasks so that you can keep these operations off the UI thread but note that these operations are still connected to the UI somehow.
Aysnc 任务是专门的线程,仍然打算与您的应用程序 GUI 一起使用,但同时保留 UI 线程的资源密集型任务。因此,当更新列表、更改视图等需要您执行一些获取操作或更新操作时,您应该使用异步任务,以便您可以将这些操作从 UI 线程中分离出来,但请注意,这些操作仍然以某种方式连接到 UI .
For longer-running tasks, which don't require UI updation, you can use services instead because they can live even without a UI.
对于不需要更新 UI 的更长时间运行的任务,您可以改用服务,因为它们甚至可以在没有 UI 的情况下继续存在。
So for short tasks, use async tasks because they can get killed by the OS after your spawning activity dies (usually will not die mid-operation but will complete its task). And for long and repetitive tasks, use services instead.
因此,对于短期任务,请使用异步任务,因为它们可能会在您的生成活动终止后被操作系统终止(通常不会在操作中终止,但会完成其任务)。对于长时间且重复的任务,请改用服务。
for more info, See threads:
有关更多信息,请参阅主题:
AsyncTask for longer than a few seconds?
and
和
回答by Arnav Rao
The problem with AsyncTask is that if it is defined as non-static inner class of the activity, it will have a reference to activity. In the scenario where activity the container of async task finishes, but the background work in AsyncTask continues, the activity object will not be garbage collected as there is a reference to it, this causes the memory leak.
AsyncTask 的问题在于,如果它被定义为活动的非静态内部类,它将拥有对活动的引用。在异步任务的容器activity结束,但AsyncTask的后台工作继续的场景下,activity对象不会因为有引用而被垃圾回收,从而导致内存泄漏。
The solution to fix this is define async task as static inner classof activity and use weak reference to context.
解决此问题的解决方案是将异步任务定义为活动的静态内部类,并使用对上下文的弱引用。
But still, it is a good idea to use it for simple and quick background tasks. To develop app with clean code, it is better to use RxJavato run complex background tasks and updating UI with results from it.
但是,将它用于简单快速的后台任务仍然是一个好主意。要使用干净的代码开发应用程序,最好使用RxJava来运行复杂的后台任务并使用其结果更新 UI。