Losing data when rotate screen
I have a little funny bug in my application. When the user rota开发者_如何学Pythontes the screen I lose some of the data in my activity. Anyone that have an idea of why this happens?
//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.
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.
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
The fastest solution I have found is this: http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
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).
In the AndroidManifest.xml add the following code
<activity android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
>
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
In the AndroidManifest.xml add the following code
<activity android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
>
It works for me
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.
configChanges solve my problem
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
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
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
}
}
精彩评论