如何在屏幕旋转期间处理 AsyncTask?
我读了很多关于如何保存实例状态或如何处理屏幕旋转期间被破坏的活动的内容。
似乎有很多可能性,但我还没有弄清楚哪一种最适合检索 AsyncTask 的结果。
我有一些 AsyncTasks 只是再次启动并调用活动的 isFinishing() 方法,如果活动完成,它们将不会更新任何内容。
问题是我有一个任务向 Web 服务发出请求,该请求可能会失败或成功,并且重新启动该任务将导致用户的经济损失。
你会如何解决这个问题?可能的解决方案有哪些优点或缺点?
I read a lot on how to save my instance state or how to deal with my activity getting destroyed during screen rotation.
There seem to be a lot of possibilities but I haven't figured out which one works best for retrieving results of an AsyncTask.
I have some AsyncTasks that are simply started again and call the isFinishing()
method of the activity and if the activity is finishing they wont update anything.
The problem is that I have one Task that does a request to a web service that can fail or succeed and restarting the task would result in a financial loss for the user.
How would you solve this? What are the advantages or disadvantages of the possible solutions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
您可以访问 code.google.com 查看我如何处理
AsyncTask
和方向更改/p/架子。有多种方法可以做到这一点,我在此应用程序中选择的方法是取消任何当前正在运行的任务,保存其状态,并在创建新的Activity
时使用保存的状态启动一个新任务。这很容易做到,效果很好,而且作为奖励,它可以在用户离开应用程序时停止你的任务。您还可以使用
onRetainNonConfigurationInstance()
将您的AsyncTask
传递给新的Activity
(注意不要泄露之前的Activity
)代码>虽然这样。)You can check out how I handle
AsyncTask
s and orientation changes at code.google.com/p/shelves. There are various ways to do it, the one I chose in this app is to cancel any currently running task, save its state and start a new one with the saved state when the newActivity
is created. It's easy to do, it works well and as a bonus it takes care of stopping your tasks when the user leaves the app.You can also use
onRetainNonConfigurationInstance()
to pass yourAsyncTask
to the newActivity
(be careful about not leaking the previousActivity
this way though.)这是我见过的关于 Android 的最有趣的问题!事实上,过去几个月我一直在寻找解决方案。还是没有解决。
请小心,仅仅覆盖这些
内容是不够的。
考虑当 AsyncTask 运行时用户接到电话的情况。您的请求已被服务器处理,因此 AsyncTask 正在等待响应。此时您的应用程序将进入后台,因为电话应用程序刚刚进入前台。操作系统可能会终止您的活动,因为它位于后台。
This is the most interesting question I've seen regarding to Android!!! Actually I've been already looking for the solution during the last months. Still haven't solved.
Be careful, simply overriding the
stuff is not enough.
Consider the case when user receives a phone call while your AsyncTask is running. Your request is already being processed by server, so the AsyncTask is awaiting for response. In this moment your app goes in background, because the Phone app has just come in foreground. OS may kill your activity since it's in the background.
我的第一个建议是确保您确实需要在屏幕旋转时重置活动(默认行为)。每次遇到旋转问题时,我都会将此属性添加到 AndroidManifest.xml 中的
标记中,一切都很好。它看起来很奇怪,但它会传递给您的 onConfigurationChanged() 方法,如果您不提供它,它除了重新测量布局之外什么也不做,这似乎是一个完美的解决方案大多数时候处理旋转的适当方法。
My first suggestion would be to make sure you actually need your activity to be reset on a screen rotation (the default behavior). Every time I've had issues with rotation I've added this attribute to my
<activity>
tag in the AndroidManifest.xml, and been just fine.It looks weird, but what it does it hand off to your
onConfigurationChanged()
method, if you don't supply one it just does nothing other than re-measure the layout, which seems to be a perfectly adequate way of handling the rotate most of the time.为什么不在Android提供的Singleton上始终保留对当前AsyncTask的引用呢?
每当任务启动时,在 PreExecute 或构建器上,您可以定义:
((Application) getApplication()).setCurrentTask(asyncTask);
每当任务完成时,您将其设置为 null。
这样,您始终拥有一个引用,允许您执行适合您的特定逻辑的 onCreate 或 onResume 之类的操作:
this.asyncTaskReference = ((Application) getApplication()).getCurrentTask();
If它是空的,你知道目前没有正在运行的!
:-)
Why don't you always keep a reference to the current AsyncTask on the Singleton provided by Android?
Whenever a task starts, on PreExecute or on the builder, you define:
((Application) getApplication()).setCurrentTask(asyncTask);
Whenever it finishes you set it to null.
That way you always have a reference which allows you to do something like, onCreate or onResume as appropriated for your specific logic:
this.asyncTaskReference = ((Application) getApplication()).getCurrentTask();
If it's null you know that currently there is none running!
:-)
最正确的方法是使用片段来通过旋转保留异步任务的实例。
这是一个非常简单示例的链接,可以轻松地将这种技术集成到您的应用程序中。
https://gist.github.com/daichan4649/2480065
The most proper way to this is to use a fragment to retain the instance of the async task, over rotations.
Here is a link to very simple example making it easy to follow integrate this technique into your apps.
https://gist.github.com/daichan4649/2480065
在
Pro android 4
中。作者提出了一个很好的方法,您应该使用弱引用
。弱引用注释
In
Pro android 4
. author has suggest a nice way, that you should useweak reference
.Weak reference note
在我看来,最好通过 onRetainNonConfigurationInstance 来存储 asynctask,将其与当前 Activity 对象解耦,并在方向更改后将其绑定到新的 Activity 对象。 在这里 我发现了一个非常好的示例,说明如何使用 AsyncTask 和 ProgressDialog。
To my point of view, it's better to store asynctask via
onRetainNonConfigurationInstance
decoupling it from the current Activity object and binding it to a new Activity object after the orientation change. Here I found a very nice example how to work with AsyncTask and ProgressDialog.Android:后台处理/带有配置更改的异步操作
要在后台进程期间维护异步操作的状态:
你可以借助碎片。
请参阅以下步骤:
步骤 1:创建一个无标头片段(例如后台任务)并在其中添加一个私有异步任务类。
步骤 2(可选步骤):如果您想将加载光标放在 Activity 顶部,请使用以下代码:
步骤 3:在主 Activity 中实现步骤 1 中定义的 BackgroundTaskCallbacks 接口
}
Android : background processing/Async Opeartion with configuration change
To maintain the states of async opeartion during background process:
you can take an help of fragments.
See the following steps :
Step 1: Create a headerless fragment let say background task and add a private async task class with in it.
Step 2 (Optional Step): if you want to put a loading cursor on top of your activity use below code:
Step 3: In your main Activity implement BackgroundTaskCallbacks interface defined in step 1
}
需要考虑的一件事是 AsyncTask 的结果是否只应可供启动该任务的活动使用。如果是,那么Romain Guy的答案是最好的。如果它应该可供应用程序的其他活动使用,那么在
onPostExecute
中,您可以使用LocalBroadcastManager
。您还需要确保活动正确处理活动暂停时发送广播的情况。
One thing to consider is whether the result of the AsyncTask should be available only to the activity that started the task. If yes, then Romain Guy's answer is best. If it should be available to other activities of your application, then in
onPostExecute
you can useLocalBroadcastManager
.You will also need to make sure that activity correctly handles situation when broadcast is sent while activity is paused.
请查看这篇帖子。这篇文章涉及 AsyncTask 执行长时间运行的操作以及在一个示例应用程序中发生屏幕旋转时的内存泄漏。示例应用程序可在 source forge 上获取
Have a look at this post. This Post involves AsyncTask performing long running operation and memory leak when screen rotation happens both in one sample application. The sample app is available on the source forge
我的解决方案。
就我而言,我有一系列具有相同上下文的 AsyncTasks。活动只能访问第一个。要取消任何正在运行的任务,我执行了以下操作:
任务
doInBackground()
:活动
onStop()
或onPause()
:My solution.
In my case i've got a chain of AsyncTasks with the same context. Activity had an access only to first one. To cancel any running task i did the following:
Task
doInBackground()
:Activity
onStop()
oronPause()
:你还可以添加
android:configChanges="keyboardHidden|orientation|screenSize"
到您的清单示例我希望它有帮助
you can also add
android:configChanges="keyboardHidden|orientation|screenSize"
to your manifest example i hope it help