【问题标题】:Losing data when rotate screen旋转屏幕时丢失数据
【发布时间】:2011-07-04 15:36:24
【问题描述】:

我的应用程序中有一个有趣的错误。当用户旋转屏幕时,我会丢失我活动中的一些数据。任何人都知道为什么会发生这种情况?

【问题讨论】:

  • 一个有趣的答案:你可以强制一个方向,使它不能旋转。如果持久性比允许轮换更重要,那么它是首选。

标签: android android-activity rotation


【解决方案1】:

默认情况下,当屏幕旋转时,您的 Activity 会被终止并重新启动。为确保没有数据丢失,您需要使用生命周期方法正确保存和恢复数据。见Saving Persistent State

【讨论】:

  • 虽然有些数据由Android保存的——例如EditText内容。
  • @RivieraKid 我不知道你是否可以依赖它。你有没有看到任何官方说是这样的?如果它实际上不在规范中,我会担心一些非品牌手机会稍微改变实施。最安全的做法是假设没有保存任何内容。
  • @CherylSimon EditTextfreezesText 属性默认设置为 true。官方文档是developer.android.com/reference/android/widget/…
【解决方案2】:
//Use onSaveInstanceState(Bundle) and onRestoreInstanceState

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {

  // Save UI state changes to the savedInstanceState.   
  // This bundle will be passed to onCreate if the process is  
  // killed and restarted.

  savedInstanceState.putBoolean("MyBoolean", true);  
  savedInstanceState.putDouble("myDouble", 1.9);  
  savedInstanceState.putInt("MyInt", 1);  
  savedInstanceState.putString("MyString", "Welcome back to Android");  

  // etc.  

  super.onSaveInstanceState(savedInstanceState);  
}  

//onRestoreInstanceState  

@Override  
public void onRestoreInstanceState(Bundle savedInstanceState) {  

  super.onRestoreInstanceState(savedInstanceState);  

  // Restore UI state from the savedInstanceState.  
  // This bundle has also been passed to onCreate.  

  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");  
  double myDouble = savedInstanceState.getDouble("myDouble");  
  int myInt = savedInstanceState.getInt("MyInt");  
  String myString = savedInstanceState.getString("MyString");  
}

当系统轮换删除数据时,这是您保存数据的方式。

【讨论】:

  • 注意! super.onSaveInstanceState(savedInstanceState) 应该在放置值之前调用。
  • onRestoreInstanceState 并不总是被调用。
【解决方案3】:

【讨论】:

  • 在这种情况下,它会保留包括布局在内的所有内容。我希望布局应随方向而变化,但对象(例如 TextView)继续显示旋转前显示的值。
  • 虽然这可能满足某些需求,但除非万不得已,否则应避免使用此解决方案。甚至在 Android 文档的开头就有一个警告。
【解决方案4】:

这是@jaisonDavis 的有用答案的变体:

int myInt;
String myString;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_verses);


    if (savedInstanceState == null) {

        Intent intent = getIntent();
        myInt = intent.getIntExtra("MyIntIntentKey", DEFAULT_INT);
        myString = intent.getStringExtra("MyStringIntentKey", DEFAULT_STRING);

    } else { // savedInstanceState has saved values

        myInt = savedInstanceState.getInt("MyIntKey");
        myString = savedInstanceState.getString("MyStringKey");
    }

}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {

    savedInstanceState.putInt("MyIntKey", myInt);
    savedInstanceState.putString("MyStringKey", myString);

    super.onSaveInstanceState(savedInstanceState);
}

在此示例中,变量在第一次创建活动时从 Intent 初始化,但之后它们从 savedInstanceState 初始化(例如当方向改变时)。

【讨论】:

    【解决方案5】:

    这将解决您保留状态的问题,但不幸的是,它仅适用于 Fragment 而不是标准的 Activity

    setRetainInstance(true);
    

    onCreate() 方法中调用它。

    【讨论】:

    • 你从哪里得到这个方法?
    • OP 问题标签是 activity 而不是 fragment
    【解决方案6】:

    AndroidManifest.xml中添加如下代码

    <activity android:name=".MainActivity" android:configChanges="keyboardHidden|orientation|screenSize" >

    【讨论】:

      【解决方案7】:

      更多详情

      人们已经提供了代码。因此,我将添加更多详细信息。

      屏幕旋转时会发生什么?

      当屏幕旋转时,Activity 的配置会发生变化,因此系统会为 Activity 寻找更合适的资源。为此,系统会终止该活动的实例并重新创建该活动的一个新实例。

      System如何创建一个新的Instance?

      系统尝试使用一组保存的旧 Activity 实例数据(称为实例状态)重新创建实例。 InstanceState 是 Key-Value 对的集合,存储在 Bundle 对象中。

      系统自动保存了一些数据

      默认情况下,系统会将 View 对象保存在 Bundle 中。

      • EditText 中的文本
      • 在 ListView 等中滚动位置

      如果您想存储更多可以在方向更改后保留下来的数据。您应该覆盖 onSaveInstanceState(Bundle savedInstanceState) 方法。

      正确使用 onSaveInstaneState

      @Override
      public void onSaveInstanceState(Bundle savedInstanceState) {
          // Save the user's current game state
          savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
      
          // Always call the superclass so it can save the view hierarchy state
          super.onSaveInstanceState(savedInstanceState);
      }
      

      所以如果你忘记打电话是错误的 super.onSaveInstanceState(savedInstanceState) 默认行为 将不起作用,即EditText 中的文本将无法保存。 如果你不相信我check this out

      用什么方法来恢复状态?

      包括我在内的许多人都感到困惑。我应该选择

      • onCreate(Bundle savedInstanceState)

      • onRestoreInstanceState(Bundle savedInstanceState)

      没关系。两种方法都在参数中接收相同的包。唯一的区别是您需要在onCreate(Bundle savedInstanceState) 方法中提供一个空检查。但是如果你要使用onRestoreInstanceState(Bundle savedInstanceState)请谨慎使用

      @Override
      public void onRestoreInstanceState(Bundle savedInstanceState) {
          // Always call the superclass so it can restore the view hierarchy
          super.onRestoreInstanceState(savedInstanceState);
      
          // Restore state members from saved instance
          mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
      }
      

      总是打电话给super.onRestoreInstanceState(savedInstanceState),这样 系统默认恢复View层级

      【讨论】:

        【解决方案8】:

        Android 引入了ViewModel,它可以在屏幕旋转时存储复杂对象。 ViewModel 类旨在以生命周期意识的方式存储和管理与 UI 相关的数据。 ViewModel 类允许数据在配置更改(例如屏幕旋转)后继续存在。

        请参考文档

        https://developer.android.com/topic/libraries/architecture/viewmodel

        【讨论】:

          【解决方案9】:

          在AndroidManifest.xml中添加如下代码

          <activity android:name=".MainActivity"
                      android:configChanges="keyboardHidden|orientation|screenSize"
                      >
          

          对我有用

          【讨论】:

            【解决方案10】:

            您可以使用 MVVM 模式并使用您的 ViewModel 来保存数据。因此,当您旋转设备时,您不必担心丢失数据,因为您在 ViewModel 中隔离了数据,这意味着您的数据不会受到活动生命周期的影响。 https://developer.android.com/topic/libraries/architecture/viewmodel

            【讨论】:

              【解决方案11】:

              configChanges 解决了我的问题

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

              【讨论】:

                【解决方案12】:

                “ViewModel”是一个设计用于在配置更改(例如屏幕旋转)后保留的类,并且可以保留视图所需的信息。当“视图”(即片段/活动)通过更改设备的配置或旋转而被破坏时,其“视图模型”不会被破坏,并且视图的新实例将重新连接到相同的“视图模型”。

                ViewModel 中的代码可能是这样的,以便 View 可以保存数据:

                private boolean mSomeBooleanData = false;
                
                public boolean getSomeBooleanData(){
                    return mSomeBooleanData;
                }
                
                public void setSomeBooleanData (boolean data) {
                    mSomeBooleanData = data;
                }
                

                现在在 Activity/Fragment 类的某处,从 ViewModel 调用这些方法,我们可以使用以下方法保存我们想要在旋转期间保存的数据:

                mViewModel.setSomeBooleanData(true);
                

                然后在 onResume() 方法中重新创建 Activity/Fragment 类时,我们可以从 ViewModel 中查找保存的数据并对其进行处理:

                public void onResume(){
                    super.onResume();
                   
                    if (mViewModel.getSomeBooleanData()){
                        //...Do something when saved data is True
                    } else {
                        //...Do something when saved data is False
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2012-04-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-10-23
                  • 1970-01-01
                  • 2014-04-20
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多