旋转屏幕时丢失数据

发布于 2024-10-19 10:20:17 字数 62 浏览 4 评论 0原文

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

I have a little funny bug in my application. When the user rotates the screen I lose some of the data in my activity. Anyone that have an idea of why this happens?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

只怪假的太真实 2024-10-26 10:20:17
//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");  
}

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

//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");  
}

This is how you save your data when the system deletes it on rotation.

软糖 2024-10-26 10:20:17

默认情况下,当屏幕旋转时,您的 Activity 将被终止并重新启动。为了确保不丢失数据,您需要使用生命周期方法正确保存和恢复数据。请参阅保存持久状态

By default, when the screen is rotated your Activity is killed and restarted. To make sure no data is lost, you need to properly save and restore your data using the lifecycle methods. See Saving Persistent State.

百善笑为先 2024-10-26 10:20:17

更多细节

人们已经提供了代码。所以我将添加更多细节。

当屏幕旋转时会发生什么?

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

系统如何创建一个新的实例?

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

系统自动保存一些数据

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

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

如果您想存储更多应在方向更改中幸存的数据。您应该重写 onSaveInstanceState(Bundle savingInstanceState) 方法。

正确使用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 中的文本将不会保存。
如果您不相信我看看这个

使用哪种方法来恢复状态?

很多人都感到困惑,包括我。我应该选择

  • onCreate(Bundle savingInstanceState)

还是

  • onRestoreInstanceState(Bundle savingInstanceState)

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

@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层级

More Detail

People have already provided the code. So I am going to add more details on that.

What happens when screen rotates?

When the screen rotates the configuration of the Activity changes so System looks for a more suitable resource for the Activity. For this purpose System kills the instance of the activity and recreates a new instance of the Activity.

How does System creates a new Instance?

System tries to recreate the instance using a set of saved data of old Activity instance known as instance state. InstanceState is a collection of Key-Value Pair stored in a Bundle object.

System saved some data automatically

By default System saves the View objects in the Bundle for example.

  • Text in EditText
  • Scroll position in a ListView etc

If you want to store more data which should survive orientation change. You should override onSaveInstanceState(Bundle savedInstanceState) method.

Use onSaveInstaneState correctly

@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);
}

So by mistake if you forget to call
super.onSaveInstanceState(savedInstanceState) the default behavior
will not work ie Text in EditText will not save.
If you don't believe me check this out

Which method to use to restore state ?

Many people get confused including me. Should I choose

  • onCreate(Bundle savedInstanceState)

OR

  • onRestoreInstanceState(Bundle savedInstanceState)

It does not matter. Both methods receive the same bundle in the parameter. The only difference is that you need to provide a null check in onCreate(Bundle savedInstanceState) method. But if you are going to use onRestoreInstanceState(Bundle savedInstanceState), use it carefully

@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);
}

Always call super.onRestoreInstanceState(savedInstanceState) so that
System restore the View hierarchy by default

埋葬我深情 2024-10-26 10:20:17

以下是 @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 初始化>(就像方向改变时一样)。

Here is a variation on @jaisonDavis's helpful answer:

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);
}

In this example the variables get initialized from an Intent on the first time the activity is created, but after that they get initialized from savedInstanceState (like when the orientation changes).

居里长安 2024-10-26 10:20:17

AndroidManifest.xml 中添加以下代码


In the AndroidManifest.xml add the following code

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

深陷 2024-10-26 10:20:17

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

请参阅文档

https://developer.android.com/topic/libraries/architecture/视图模型

Android has introduced ViewModel which can store Complex Objects when Screen is rotated.
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

Please refer to docs

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

情绪少女 2024-10-26 10:20:17

在 AndroidManifest.xml 添加以下代码

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

它对我有用

In the AndroidManifest.xml add the following code

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

It works for me

私藏温柔 2024-10-26 10:20:17

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

setRetainInstance(true);

onCreate() 方法中调用它。

This will solve your issue of retaining state, but it only works for a Fragment and not a standard Activity unfortunately.

setRetainInstance(true);

Call this in the onCreate() method.

稍尽春風 2024-10-26 10:20:17

configChanges 解决了我的问题

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

configChanges solve my problem

<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
      android:label="@string/app_name">
謸气贵蔟 2024-10-26 10:20:17

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

You can use MVVM pattern and use your ViewModel to save your data. So when you rotate your device you won't be worry about losing your data because you isolated your data in the ViewModel and that means your data won't be affected by activity lifecycle.
https://developer.android.com/topic/libraries/architecture/viewmodel

呆° 2024-10-26 10:20:17

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

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

private boolean mSomeBooleanData = false;

public boolean getSomeBooleanData(){
    return mSomeBooleanData;
}

public void setSomeBooleanData (boolean data) {
    mSomeBooleanData = data;
}

现在在 Activity/Fragment 类中的某个位置,从 ViewModel 调用这些方法,我们可以保存 然后,当在 onResume () 方法中重新创建 Activity/Fragment类

mViewModel.setSomeBooleanData(true);

时,我们可以从 ViewModel 中查找保存的数据并对其执行某些操作:

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

A “ViewModel” is a class designed to survive configuration changes (e.g., screen rotation) and can preserve the information necessary for the View. When “View” (i.e. fragment/activity) is destroyed by changing the configuration or rotation of the device, its “ViewModel” will not be destroyed and a new instance of View will be reconnected to the same “ViewModel”.

This is what the code in ViewModel might look like so that View can save the data:

private boolean mSomeBooleanData = false;

public boolean getSomeBooleanData(){
    return mSomeBooleanData;
}

public void setSomeBooleanData (boolean data) {
    mSomeBooleanData = data;
}

Now somewhere in the Activity/Fragment class, calling these methods from the ViewModel we can save the data we want to save during rotation using:

mViewModel.setSomeBooleanData(true);

Then when recreating the Activity/Fragment class in the onResume () method, we can look for that saved data from the ViewModel and do something with it:

public void onResume(){
    super.onResume();
   
    if (mViewModel.getSomeBooleanData()){
        //...Do something when saved data is True
    } else {
        //...Do something when saved data is False
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文