【问题标题】:onCreate(...) is called twice after the device is rotatedonCreate(...) 在设备旋转后被调用两次
【发布时间】:2017-10-04 02:51:53
【问题描述】:

我有一个关于旋转 Android 设备的问题。我的代码在 onCreate(...) 中记录了一个静态和非静态属性。

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
    static int sn;
    int n;

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

        sn++;
        n++;

        Log.i("onCreate", String.format("sn=%d n=%d", sn, n));
    }
}

屏幕方向为纵向。当我第一次运行代码时,我得到了:

onCreate(): sn=1 n=1

将屏幕旋转到横向后,我得到:

onCreate(): sn=2 n=1

在我再次将屏幕旋转为纵向后,我得到了:

onCreate(): sn=3 n=1
onCreate(): sn=4 n=1

我的问题是:

  1. 当设备旋转回纵向时,如何防止 onCreate(...) 被调用两次?
  2. 如何在设备旋转时保存非静态变量的值?

【问题讨论】:

标签: android


【解决方案1】:

这是模拟器中的一个已知问题(请参阅讨论here)。这不是一个错误,但对于许多人来说,这是一个问题。据我了解,基本问题是您的活动在进入纵向模式时会重新启动两次,因为模拟器正在分别处理两个配置更改:方向更改本身和键盘的停用。它不会在另一个方向发生,因为没有对应于键盘激活的配置更改事件。 (我觉得这很奇怪,但显然出于某种原因这是期望的行为。)

无论如何,解决方案似乎是将其添加到您的活动清单声明中:

android:configChanges="keyboardHidden|orientation"

如果您确实需要这些更改来加载新资源,您可以在 onConfigurationChanged 中手动处理。

【讨论】:

  • +1;有趣的。我什至从未注意到它被调用了两次(或者它是否应该重要)。
  • +1:在模拟器上注意到它,但从不打扰我用真实设备进行测试(回到 1.6/2.x 天)。从那以后就不再依赖模拟器了。
  • 我不得不用它来覆盖所有的基础:keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize
  • android:configChanges="keyboard|keyboardHidden|orientation|screenSize" 我已经添加了。谢谢。
  • 不仅适用于模拟器,它在真实设备上的行为也相同,而且 configChanges 对我不起作用:(
【解决方案2】:

每当屏幕方向发生变化时,该 Activity 就会被销毁,并通过 onCreate() 方法启动一个新的 Activity。 因此,每次您旋转屏幕时,该活动都将被销毁,并通过onCreate() 方法启动一个新活动。 您可以通过覆盖onSaveInstanceState(Bundle b) 方法来保存非静态成员。 每当屏幕旋转时,Android 都会调用此方法,并且给定的包 b 将被传递给 oncreate(Bundle b),您可以从中提取非 static 成员。

【讨论】:

  • 我覆盖了onSaveInstanceState(Bundle savedInstanceState),但是当我旋转我的模拟器时它没有被调用。
  • 您可能没有正确地覆盖该方法,它是在 onPause() 之前调用的。
  • @Override protected void onSaveInstanceState(Bundle bundle1){ super.onSaveInstanceState(bundle1); Log.i(tag,"inside onSaveInstanceState"); bundle1.putInt("变量 n",n); bundle1.putInt("sn",sn); }
  • 我知道我在 Log.i(tag, msg)` 的 onSaveInstanceState(...). It is because the tag` 参数中看不到日志消息的原因太长了。非常感谢您的回复。
【解决方案3】:

不知道onCreate 的问题;这些调用来自操作系统。

非静态(“实例”)变量应保存在instanceState;这就是它的用途。请参阅总结它的posts like this,或讨论应用程序生命周期的大多数基本 Android 教程。

【讨论】:

  • onSaveInstanceState(...) 在我旋转模拟器时不会被调用。而onPause() 不接受任何Bundle。我在哪里可以保存instanceState
  • @user639616 你确定吗?应该是,因为活动被销毁并重新创建。
  • 我覆盖了onSaveInstanceState(Bundle savedInstanceState) 并记录了一些消息。但我看不到日志消息。
  • 我知道我在 Log.i(tag, msg)` 的onSaveInstanceState(...). It is because the tag` 参数中看不到日志消息的原因太长了。非常感谢您的回复。
【解决方案4】:

这很简单:您可以在代码中覆盖 onConfigurationChanged() 方法。

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

    }

所以现在你的非静态变量不会受到影响,因为此时你的 Activity 没有被销毁,也没有一个新的 Activity 由 onCreate() 方法启动。

【讨论】:

  • 我还需要在manifest文件中设置属性android:configChanges="keyboardHidden|orientation"吗?
  • 这是必需的!!!仅当您设置属性 android:configChanges 时才会调用 onConfigurationChanged !
【解决方案5】:

每次旋转屏幕时都会重新创建活动 -- 这是 android 的概念。

但在你的情况下,当活动重新创建时,静态值将被保留..而non static 将被重新初始化......所以你总是得到n=1......

如果您真的想保留该非静态值,请转到Shared Preferences。在这种情况下,您可以保留所需的所有值,直到用户清除数据....

否则只需将non static 改为static,我猜这可能会解决您的问题

【讨论】:

    【解决方案6】:

    将此行放在 AndroidManifest.xml 文件中的 Activity 中:

    android:launchMode="singleInstance"
    

    来自Documentation

    singleTask”和“singleInstance”活动只能开始一个任务。 它们始终位于活动堆栈的根部。此外, 设备一次只能保存一个活动实例——只有一个 这样的任务。

    另一方面,“singleInstance”活动不允许其他活动 活动成为其任务的一部分。这是任务中的唯一活动。 如果它开始另一个活动,则将该活动分配给一个 不同的任务——就好像FLAG_ACTIVITY_NEW_TASK 的意图一样。

    【讨论】:

      猜你喜欢
      • 2012-12-15
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-03
      • 1970-01-01
      相关资源
      最近更新 更多