我下载了一些数据从互联网在后台线程(我使用AsyncTask)和显示进度对话框,而下载。方向改变,活动重新启动,然后我的AsyncTask完成-我想解散进程对话框,并启动一个新的活动。但是调用disdisdialog有时会抛出一个异常(可能是因为Activity已经被销毁并且新的Activity还没有启动)。

处理这类问题的最佳方法是什么(从后台线程更新UI,即使用户改变方向也能工作)?谷歌是否有人提供了一些“官方解决方案”?


当前回答

虽然Mark (CommonsWare)的答案确实适用于方向更改,但如果Activity被直接销毁(比如在电话的情况下),它就会失败。

你可以通过使用一个应用对象来引用ASyncTask来处理方向变化和很少被破坏的Activity事件。

对于这个问题和解决方案,这里有一个很好的解释:

这一点完全要归功于瑞恩。

其他回答

4年后,谷歌解决了问题,只是在onCreate活动中调用setRetainInstance(true)。它将在设备旋转期间保存您的活动实例。对于旧版本的Android,我也有一个简单的解决方案。

谷歌是否有人提供了一些“官方解决方案”?

Yes.

解决方案更像是一个应用程序体系结构建议,而不仅仅是一些代码。

他们提出了3种设计模式,允许应用程序与服务器同步工作,无论应用程序状态如何(即使用户完成应用程序,用户更换屏幕,应用程序被终止,任何其他可能的状态,后台数据操作可能被中断,它也会工作,这包括在内)

Virgil Dobjanschi在谷歌I/O 2010期间的Android REST客户端应用程序演讲中解释了这个提议。它只有1小时长,但非常值得一看。

它的基础是将网络操作抽象为独立于应用程序中的任何活动的服务。如果您正在使用数据库,使用ContentResolver和Cursor将为您提供一个开箱即用的Observer模式,一旦您使用获取的远程数据更新了本地数据库,就可以方便地更新UI,而无需任何额外的逻辑。任何其他后续操作代码都将通过传递给服务的回调运行(为此我使用ResultReceiver子类)。

不管怎样,我的解释其实很模糊,你一定要看这个演讲。

这是我的解决方案:https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog

基本步骤如下:

我使用onSaveInstanceState保存任务,如果它仍然 处理。 在onCreate我得到的任务,如果它被保存。 在onPause我放弃ProgressDialog如果它是显示。 在onResume中,如果任务仍然,我将显示ProgressDialog 处理。

您应该使用活动处理程序调用所有活动操作。因此,如果你在某个线程中,你应该创建一个Runnable,并使用活动的处理程序发布。否则你的应用程序有时会崩溃,出现致命异常。

步骤#1:使AsyncTask成为一个静态嵌套类,或者一个完全独立的类,只是不是一个内部(非静态嵌套)类。

步骤#2:让AsyncTask通过一个数据成员保存活动,通过构造函数和setter设置。

步骤#3:当创建AsyncTask时,将当前Activity提供给构造函数。

步骤#4:在onRetainNonConfigurationInstance()中,返回AsyncTask,在将它从原始的,现在正在消失的活动中分离出来之后。

步骤#5:在onCreate()中,如果getLastNonConfigurationInstance()不为空,将其转换为AsyncTask类,并调用setter将新活动与任务关联起来。

步骤#6:不要引用doInBackground()中的活动数据成员。

如果你按照上面的食谱做,一切都会成功的。onProgressUpdate()和onPostExecute()被挂起在onRetainNonConfigurationInstance()的开始和后续onCreate()的结束之间。

下面是演示该技术的示例项目。

Another approach is to ditch the AsyncTask and move your work into an IntentService. This is particularly useful if the work to be done may be long and should go on regardless of what the user does in terms of activities (e.g., downloading a large file). You can use an ordered broadcast Intent to either have the activity respond to the work being done (if it is still in the foreground) or raise a Notification to let the user know if the work has been done. Here is a blog post with more on this pattern.