[Android问答] 旋转屏幕导致Activity重建怎么办?

[Android问答] 旋转屏幕导致Activity重建怎么办?

Android开发文档上专门有一小节解释这个问题。简单来说,Activity是负责与用户交互的最主要机制,任何“设置”(Configuration)的改变都可能对Activity的界面造成影响,这时系统会销毁并重建Activity以便反映新的Configuration。

“屏幕方向”(orientation)是一个Configuration,通过查看Configuration类的javadoc可以看到其他Configuration还有哪些:如fontScale、keyboardHidden和locale等等。

当屏幕旋转时,这个Configuration就发生了改变,因此当前显示的Activity需要被重建,Activity对象会被终止,它的onPause()、onStop()和onDestroy()方法依次触发,然后一个新的Activity对象被创建,onCreate()方法被触发。假设屏幕旋转前,用户正在手机上填写一个注册表单,如果处理不当,用户会发现旋转后的表单变成空白的了,严重影响使用体验。

要解决这个问题有三种方法:

方法1:禁止旋转屏幕

毫无疑问,这是最懒的办法了,相当于回避了本文提出的问题,方法如下看看就好:

<activity android:name=".MyActivity"
          android:screenOrientation="portrait"
          android:label="@string/app_name">

方法2:旋转后恢复现场

既然Activity会被销毁,那么我们就可以使用前文介绍过的“持久化/恢复现场”方法来解决。即在onPause()里将用户当前已经输入的内容保存到数据库或Preference,在onCreate()方法里读取并填充到表单中,这也是官方推荐的方法。

需要补充一点,如果Activity重建需要耗费大量资源或需要访问网络导致时间很长,可以实现onRetainNonConfigurationInstance()方法将所需数据先保存到一个对象里,像下面这样:

@Override
public Object onRetainNonConfigurationInstance() {
    final MyDataObject data = collectMyLoadedData();
    return data;
}

重建时,在onCreate()方法里通过getLastNonConfigurationInstance()方法获得之前保存的数据,如下所示:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
    if (data == null) {//表示不是由于Configuration改变触发的onCreate()
        data = loadMyData();
    }
    ...
}

方法3:手工处理旋转

一般情况下Configuration的改变会导致Activity被销毁重建,但也有办法让指定的Configuration改变时不重建Activity,方法是在AndroidManifest.xml里通过android:configChanges属性指定需要忽略的Configuration名字,例如下面这样:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

这样设置以后,当屏幕旋转时Activity对象不会被销毁——作为替代,Activity的onConfigurationChanged()方法被触发,在这里开发者可以获取到当前的屏幕方向以便做必要的更新。既然这种情况下的Activity不会被销毁,旋转后Activity里正显示的信息(例如文本框中的文字)也就不会丢失了。

假如你的应用里,横屏和竖屏使用同一个layout资源文件,onConfigurationChanged()里甚至可以什么都不做。但如果横屏与竖屏使用不同的layout资源文件,例如横屏用res/layout-land/main.xml,竖屏用res/layout-port/main.xml,则必须在onConfigurationChanged()里重新调用setContentView()方法以便新的layout能够生效,这时虽然Activity对象没有销毁,但界面上的各种控件都被销毁重建了,你需要写额外的代码来恢复界面信息。

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "横屏模式", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "竖屏模式", Toast.LENGTH_SHORT).show();
    }
}

官方的Android开发文档不建议使用这种方式处理Configuration改变:

Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.

最佳实践

考虑到旋转屏幕并不是使Activity被销毁重建的唯一因素,仍然推荐前文介绍过的方法:在onPause()里持久化Activity状态,在onCreate()里恢复现场,可以做到一举多得;虽然Google不推荐设置android:configChanges属性的方式,但如果你的Activity横向纵向共用同一个layout文件,方法3无疑是最省事的。

参考资料:

Configuration Changes 
Handling Runtime Changes
Activity restart on rotation Android
How to handle screen orientation change when progress dialog and background thread active?

本文转自博客园八进制的博客,原文链接:[Android问答] 旋转屏幕导致Activity重建怎么办?,如需转载请自行联系原博主。

时间: 2024-10-24 16:42:54

[Android问答] 旋转屏幕导致Activity重建怎么办?的相关文章

Android开发 旋转屏幕导致Activity重建解决方法_Android

Android开发文档上专门有一小节解释这个问题.简单来说,Activity是负责与用户交互的最主要机制,任何"设置"(Configuration)的改变都可能对Activity的界面造成影响,这时系统会销毁并重建Activity以便反映新的Configuration. "屏幕方向"(orientation)是一个Configuration,通过查看Configuration类的javadoc可以看到其他Configuration还有哪些:如fontScale.ke

Android开发 旋转屏幕导致Activity重建解决方法

Android开发文档上专门有一小节解释这个问题.简单来说,Activity是负责与用户交互的最主要机制,任何"设置"(Configuration)的改变都可能对Activity的界面造成影响,这时系统会销毁并重建Activity以便反映新的Configuration. "屏幕方向"(orientation)是一个Configuration,通过查看Configuration类的javadoc可以看到其他Configuration还有哪些:如fontScale.ke

Android webview旋转屏幕导致页面重新加载问题解决办法

Android webview旋转屏幕导致页面重新加载问题解决办法 1. 在create时候加个状态判断 protected void onCreate(Bundle savedInstanceState){ ... if (savedInstanceState == null) { mWebView.loadUrl("your_url"); } ... } 2. 重载保存状态的函数: @Override protected void onSaveInstanceState(Bundl

android-Android 自动旋转屏幕快捷开关,系统会发送广播吗?

问题描述 Android 自动旋转屏幕快捷开关,系统会发送广播吗? 10C 就是下图这里的自动旋转屏幕开关,开启和关闭自动旋转系统会发送广播吗?什么广播?怎么监听它的状态改变? 解决方案 屏幕旋转开关: 1). 屏幕旋转开关设置主要调用android.provider.Settings.System的putInt和getInt方法实现. 2). 通过ContentObserver来动态观察屏幕旋转设置的改变. 示例代码如下: package com.example.srs; import and

android-旋转屏幕时Activity重启的问题

问题描述 旋转屏幕时Activity重启的问题 在程序中有两个不同的布局文件,一个纵向模式,一个是横向模式.当我旋转屏幕时, onCreate方法重启程序,重新创建所有的元素.所以在manifest文件中设置 android:configChanges=""orientation"" 再次旋转屏幕时,onCreate方法不被调用了,但是新布局显示的也不正确.在Activity中添加以下代码,依然不正确. @Overridepublic void onConfigur

[Android问答] 如何应对Activity进程被杀?

[Android问答] 如何应对Activity进程被杀? 我们要了解Android手机开发与桌面开发有一个主要不同之处:通常在一部Android手机里同时运行着多个应用(app),每个app对应一个系统进程,当系统需要更多的资源(如内存)而空闲资源不足时,Android系统就会选择杀掉一些"低优先级"的进程以便释放所需资源. Android系统是如何确定进程优先级的高低的呢? 如果一个app正在与用户交互,那么它所在的进程具有最高优先级: 其次,如果一个app是可见的,例如被一个对话

[Android问答] 如何获得手机屏幕分辨率?

[Android问答] 如何获得手机屏幕分辨率? 这个问题并不复杂,但是问的人实在很多,所以还是集中回答一下. 从Android 3.2(API Level 13)开始,在Activity里使用下面的方法来获取屏幕分辨率(单位是像素): Display display = getWindowManager().getDefaultDisplay(); //Activity#getWindowManager() Point size = new Point(); display.getSize(s

[Android问答] 如何理解Activity生命周期?

[Android问答] 如何理解Activity生命周期? Android官方文档里对Activity的生命周期有比较详尽的描述,但由于资源回收机制带来不确定性,我们的程序运行结果常常与预期的不符,而调试这类问题又十分消耗时间和精力.解决的根本办法还是要理解透Activity的生命周期及相关内容,这篇帖子着重介绍Activity生命周期本身,之后会用一两篇帖子来介绍如何处理异常的状态变化. 下图是官方文档里的Activity生命周期图,其中彩色标出的四个框是Activity的四种状态,当Acti

关于Android横竖屏切换及Activity重启周期的总结

禁止Android横竖屏和解决切换屏幕时重启Activity的方法 1.在AndroidManifest.xml的Activity配置中加入 android:screenOrientation="landscape"属性(landscape是横向,portrait是纵向).如: <activity android:name=".ContactsManagerActivity" android:label="@string/app_name"