【Android】屏幕翻转(screen orientation change)

博客整理自:How to handle screen orientation change when progress dialog and background thread active?

初始问题是:提问者有一个程序,后台跑网络进程,前台有一个ProgressDialog显示下载进程,一切工作良好,但是当这种情况下翻转屏幕(屏幕朝向变化)的时候,程序就会崩溃,求解。作者的一个解决方案是在onSaveInstanceState中dismiss Dialog,但是这个时候进程还是在运行,似乎需要在翻转发生的时候先kill所有的东东,之后再重新运行。

 

答案一:回答者觉得When you switch orientations, Android will create a new View. You're probably getting crashes because your background thread is trying to change the state on the old one. (It may also be having trouble because your background thread isn't on the UI thread)。后台进程还在更新原先的界面,但是实际上界面已经被改变了。(说出了程序崩溃的原因)

 

答案二:在AndroidManifest.xml文件中添加语句:

1 android:configChanges="orientation"

也就是:

1 <activity 
2         android:label="@string/app_name" 
3         android:configChanges="orientation|keyboardHidden" 
4         android:name=".your.package">  

这样的话,根据developer的描述:

In some special cases, you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with theandroid:configChanges attribute in its manifest. For any types of configuration changes you say that you handle there, you will receive a call to your current activity's onConfigurationChanged(Configuration) method instead of being restarted. If a configuration change involves any that you do not handle, however, the activity will still be restarted and onConfigurationChanged(Configuration) will not be called.

还需要加入权限:

1 <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>

通过这种方式,我们可以避免重新调用OnCreate()这个方法,我们只需要在onConfigurationChanged里面改变需要改变的东西即可。(这个可以解决“View not attached to window manager”异常)

 

答案三:答题者想出了一个比较靠谱的方案,将耗时的任务放置在IntentService(这个类会独开线程做事)里面,然后将数据保存在DB里面,每次更新数据都发出broadcast以便更新数据,这样就算Activity重新启动也不会出现问题。

 

答案四:onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法

Android横竖屏切换时会触发onSaveInstanceState,而还原时会产生onRestoreInstanceState,但是Android的Activity类还有一个方法名为onRetainNonConfigurationInstance和getLastNonConfigurationInstance这两个方法。当Device configuration发生改变时,将伴随Destroying被系统调用。通过这个方法可以像onSaveInstanceState()的方法一样保留变化前的Activity State,最大的不同在于这个方法可以返回一个包含有状态信息的Object,其中甚至可以包含Activity Instance本身。新创建的Activity可以继承大量来至于Parent Activity State信息。

我们可以通过  onRetainNonConfigurationInstance 代替 onSaveInstanceState,比如:

1 @Override
2   public Object onRetainNonConfigurationInstance() 
3  {    
4        //这里需要保存的内容,在切换时不是bundle了,我们可以直接通过Object来代替
5       return obj;
6  }

 在恢复窗口时,我们可以不使用 onRestoreInstanceState,而代替的是 getLastNonConfigurationInstance 方法。我们可以直接在onCreate中使用,比如

1  Object obj = getLastNonConfigurationInstance();     最终obj的内容就是上次切换时的内容。

这个方法最大的好处是:
    * 当Activity曾经通过某个资源得到一些图片或者信息,那么当再次恢复后,无需重新通过原始资源地址获取,可以快速的加载整个Activity状态信息。
    * 当Activity包含有许多线程时,在变化后依然可以持有原有线程,无需通过重新创建进程恢复原有状态。
    * 当Activity包含某些Connection Instance时,同样可以在整个变化过程中保持连接状态。

下边是需要特别注意的几点:
    * onRetainNonConfigurationInstance()在onSaveInstanceState()之后被调用。

    * 调用顺序同样介于onStop() 和 onDestroy()之间。

posted @ 2012-11-13 14:50  大脚印  阅读(833)  评论(0编辑  收藏  举报