题 在Android上旋转活动重启


在我的Android应用程序中,当我旋转设备(滑出键盘)然后我的 Activity 重启(onCreate 叫做)。现在,这可能是它应该如何,但我做了很多初始设置 onCreate 方法,所以我需要:

  1. 将所有初始设置放在另一个功能中,这样就不会在设备旋转时丢失或
  2. 这样做 onCreate 不再调用,布局只是调整或
  3. 将应用限制为只限肖像,以便 onCreate 不叫。

1224
2018-01-19 00:28


起源


关于如何在活动配置更改期间保留长时间运行的异步任务,有一个相当完整的解释 这篇博文 太! - Adrian Monk
这不是其他人已经回答的直接答案,但我邀请您一起来看看 LogLifeCycle 了解Android应用程序中有关生命周期的内容。 - Snicolas
这是Android屏幕旋转时发生的情况。 - Ajit Singh


答案:


使用应用程序类

根据您在初始化中所做的操作,您可以考虑创建一个扩展的新类 Application 并将初始化代码移动到重写 onCreate 该类中的方法。

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

onCreate 在应用程序类中仅在创建整个应用程序时调用,因此在方向或键盘可见性更改时重新启动的活动不会触发它。

最好将此类的实例公开为单例,并使用getter和setter公开您正在初始化的应用程序变量。

注意:您需要在清单中指定新Application类的名称,以便注册和使用它:

<application
    android:name="com.you.yourapp.MyApplicationClass"

对配置更改做出反应  [更新:自API 13以来已弃用; 看到推荐的替代方案]

作为另一种选择,您可以让应用程序侦听可能导致重新启动的事件(如方向和键盘可见性更改),并在您的活动中处理它们。

首先添加 android:configChanges 节点到Activity的清单节点

android:configChanges="keyboardHidden|orientation"

或者 Android 3.2(API级别13)和更新版本

android:configChanges="keyboardHidden|orientation|screenSize"

然后在Activity中覆盖 onConfigurationChanged 方法和电话 setContentView 强制GUI布局在新方向中重新完成。

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}

897
2018-01-19 08:47



我不认为第二种方法有效。我尝试过这个;一个带有EditText的Activity。我在那里写了一些文字,改变方向,文字消失/重置。 - Ted
这里希望我们将来会看到一个onRotate()方法。甚至担心这样的事情 - 坦率地说是令人沮丧的。 - Kelly Sutton
注意 Android开发指南 警告不要使用此: 注意:使用(android:configChanges)应避免使用,仅作为最后手段使用。有关如何正确处理因配置更改而导致重新启动的信息,请阅读处理运行时更改。  作为替代,为了在旋转事件中保持数据,他们似乎更喜欢使用 onSaveInstanceState Bundle;或者作为@ Jon-O 提到, onRetainNonConfigurationInstance。 - Jeffro
这是一个糟糕的解决方案,因为它只会对此做出反应 目前已知 配置更改。对于较新的Android版本,可能会发生其他配置更改,此代码无法捕获(因为它必须列出清单中的所有配置更改)。保存国家的解决方案 onRetainNonConfigurationChanges 更具容错性和直接性。 - Bananeweizen
我想你应该补充一下 3.2的更新 对你的答案来说,这非常重要(只是遇到了这个问题)而且可能会被忽视。 - bigstones


Android 3.2及更高版本的更新:

警告:从Android 3.2开始(API级别13), “屏幕尺寸”也会发生变化 当设备在纵向和横向之间切换时。因此,如果要在开发API级别13或更高级别(由minSdkVersion和targetSdkVersion属性声明)时因为方向更改而阻止运行时重新启动,则必须包括 "screenSize" 价值除了 "orientation" 值。也就是说,你必须申报 android:configChanges="orientation|screenSize"。但是,如果您的应用程序的目标是API级别12或更低,那么您的活动始终会自行处理此配置更改(即使在Android 3.2或更高版本的设备上运行,此配置更改也不会重新启动您的活动)。


175
2018-03-03 21:56



感谢您的澄清,因为上面的评论几乎让我想一想。我目前的目标是API 8,我的代码在configChanges上没有screenSize,并且可以确认它在我运行ICS的设备上工作正常(没有重新定向)。 - Carl
感谢你指出这一点,我只有android:configChanges =“orientation | screenSize”设置,方向切换正在重新创建我的Activity,而对于我的生活,我无法弄清楚为什么! - Christopher Perry
谢谢格罗姆。你救了我的一天。我正在使用ICS并使用android:configChanges =“orientation | keyboardHidden”,这正在重新创建我的活动,但你的建议就像魔术一样! - AndroidGuy
添加android:configChanges 应该只作为最后的手段。考虑使用 Fragments 和 setRetainInstance 代替。 - Simon Forsberg
关键是 screenSize 对于Android 3.2及更高版本,这解决了我的问题,谢谢! - fantouch


而不是试图阻止 onCreate() 从完全被解雇,也许尝试检查 Bundle  savedInstanceState 被传递到事件中以查看它是否为null。

例如,如果我有一些应该在运行时运行的逻辑 Activity 是真正的创造,而不是每一个方向的改变,我只是在那里运行那个逻辑 onCreate()只有当 savedInstanceState 一片空白。

否则,我仍然希望布局能够正确地重新绘制方向。

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

不确定这是否是最终的答案,但它对我有用。


110
2017-08-04 21:04



你在哪里实际上拯救国家? - Ewoks
这似乎对我有用,它似乎是迄今为止最简单的方法。我注意到你只有4个ups(包括我的5个)而373个关于子类化Application的想法,这对我来说似乎要复杂得多。这种方法有什么缺点吗? - steveh
这个解决方案对我很有用。我以前可以 Intent serverintent = new Intent(MainActivity.this, MessageListener.class); 和 startService(serverintent); 创造一个 serverSocket = new ServerSocket(0xcff2); 和 Socket client = serverSocket.accept(); 用一个 BufferedReader(new InputStreamReader(client.getInputStream())); 并且可以旋转我的android并保持客户端/服务器连接处于活动状态,然后让GUI旋转。根据手册,savedInstanceState在最后一个活动关闭时被初始化。 - Fred F
我不明白,有什么收获?这种方法效果很好,并且复杂程度远低于其他任何解决方案。 - RTF
这是在Android中执行此操作的正确方法。基本上用configChanges捕捉旋转的其他方法以及所有笨重,复杂和不必要的方法。 - LukeWaggoner


我做了什么...

在清单中,到活动部分,添加:

android:configChanges="keyboardHidden|orientation"

在活动的代码中,实现了:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}

93
2018-01-04 01:26



澄清:通过我的实现,您现在可以在onCreate()中进行变量初始化,并且只需调用onConfigurationChanged()进行屏幕旋转。你的变量现在与屏幕旋转绝缘;-) nice和ez - Someone Somewhere
我按照这里的描述做了所有事情,但是当我尝试在方向改变后按下按钮时,我得到NullPointerException。可能有什么不对? - Finnboy11
添加android:configChanges 应该只作为最后的手段。考虑使用 Fragments 和 setRetainInstance 代替。 - Simon Forsberg
请记住,我的答案就像3岁,Android不断发展......西蒙 - 你有一个示例代码的链接吗?这就是人们的需要。 - Someone Somewhere
当对android:configChanges发出警告时,@SimonAndréForsberg实际上只是在解读 Android文档。 处理运行时更改 有更多关于替代品的详细信息(包括样本代码)。 - Leif Arne Storset


您描述的是默认行为。您必须通过添加以下内容来自行检测和处理这些事件:

android:configChanges

到您的清单,然后是您想要处理的更改。因此,对于方向,您将使用:

android:configChanges="orientation"

并且对于打开或关闭的键盘,您将使用:

android:configChanges="keyboardHidden"

如果你想要处理两者,你可以使用管道命令将它们分开,如:

android:configChanges="keyboardHidden|orientation"

这将在您调用的任何Activity中触发onConfigurationChanged方法。如果覆盖该方法,则可以传入新值。

希望这可以帮助。


57
2018-01-19 02:28



请参阅下面的答案,注意到这一点 android:configChanges="orientation" 似乎只是在模拟器中触发错误,至少对于Android 2.1而言。 - Liudvikas Bukys
添加android:configChanges 应该只作为最后的手段。考虑使用 Fragments 和 setRetainInstance 代替。 - Simon Forsberg
@GregD我知道,这就是为什么现在是更新它以反映今天情况的好时机。鉴于这个问题的赞成数量,它仍然从其他关于SO的问题中提及。 - Simon Forsberg


我刚刚发现了这个传说:

通过方向更改保持活动生效,并通过处理 onConfigurationChanged文件 和 上面的代码示例 在Manifest文件中建议:

android:configChanges="keyboardHidden|orientation"

它具有始终有效的额外好处。

奖金传说是省略了 keyboardHidden 看似合乎逻辑,但它会导致模拟器出现故障(至少对于Android 2.1):仅指定 orientation 将使模拟器调用两者 OnCreate 和 onConfigurationChanged 有时,只有 OnCreate 其他时间。

我没有看到设备上的故障,但我听说模拟器失败了。所以值得记录。


39
2017-12-22 21:50



我可以确认模拟器只是“方向”完全错误。我已经花了一夜从头发中撕下我的头发,只是碰到了你的修复工作。 - locka
警告:从Android 3.2(API级别13)开始,当设备在纵向和横向之间切换时,“屏幕大小”也会更改。因此,如果您希望在开发API级别13或更高级别时因为方向更改而阻止运行时重新启动:android:configChanges =“orientation | keyboardHidden | screenSize” - Geltrude
是的,模拟器很糟糕。您不能依赖它来准确报告配置更改。 - Igor Ganapolsky
添加android:configChanges 应该只作为最后的手段。考虑使用 Fragments 和 setRetainInstance 代替。 - Simon Forsberg


您还可以考虑使用Android平台在方向更改中保持数据的方式: onRetainNonConfigurationInstance() 和 getLastNonConfigurationInstance()

这允许您在配置更改中保留数据,例如您可能从服务器提取获取的信息或其他已在计算中获取的信息 onCreate 或者,同时也允许Android重新布局你的 Activity 使用xml文件进行正在使用的方向。

看到 这里 要么 这里

应该注意的是,这些方法现在已被弃用(尽管仍然比上述大多数解决方案建议的更方便处理方向更改)并建议每个人切换到 Fragments 而是使用 setRetainInstance(true) 在各个 Fragment 你想保留。


33
2017-09-22 03:03



我真的认为Fragments和setRetainInstance是最好的方式(谷歌的推荐方式)来做到这一点,+1给你,-1给所有其他人。添加android:configChanges 应该只作为最后的手段 - Simon Forsberg