The Android docs say that configuration changes can force an activity to be recreated, the most common change being a rotation. Now, there are some methods that can determine whether an activity is being destroyed to be recreated but all(?) of these methods are called after onStop() and aren't guaranteed or recommended for data saving purposes.
To give an example, there is an EditText activity which autosaves what they have written/updated if the user navigates away from the app via back button, app switch, e.t.c. However, the user might not want to save their changes when there is a configuration change so I need to be prepared for those cases.
When an activity is destroyed by the system because of configuration change onSaveInstanceState is called.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
Store data that you want to persist in outState bundle.
Then you'll receive the stored data in onCreate and onRestoreInstanceState.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
Use it to retrieve data you had stored in onSaveInstanceState earlier.
By default System saves the state of few widgets (EditText , TextView) on it's own and this magic happens in super.onSaveInstanceState().
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
So if you do not want to save the text in EditText , just do editText.setText("") before calling super.onSaveInstanceState().
Hope this helps.
Related
I would like my application to save state after it already has loaded once. For example in one of my activities I have a ListView. If the user scrolls it, and than switches activities, I wish for them to go back to the ListView activity and have the same scrolling position. I noticed that pressing the back button goes back to a saved version of the state. This is the exact kind of save I want (where it saves the state of the previous activity). Except I want to do this from anywhere in the application, not just when the back button is pressed... Please help me.
You have to override onSaveInstanceState(Bundle savedInstanceState) and store the values you want to save in Bundle object as name value pair.
#Override public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean("position", 12);
savedInstanceState.putString("Name", "John");
}
also you have to override onRestoreInstanceState() where you'd extract the values:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean myPosition=savedInstanceState.getBoolean("position");
String name= savedInstanceState.getString("Name");
}
see this link for help LINK
It can be done with the saveInstanceState() and onRestoreInstanceState() methods. The first one called near onPause(), the second called before onResume(). To save the state of a view, call onSaveInstanceState() from view.
For example, listview.onSaveInstnceState();
Here's a detailed article
https://futurestud.io/blog/how-to-save-and-restore-the-scroll-position-and-state-of-a-android-listview
I need to design a Android app that connect with a mysql server. I need a login system for my app.
I am just confused when and how i should use onResume and onPause methods. When user types in username and password , if he/she switch to portrait to landscape or vise versa or if gets a phone call, my app would get crashed.
And while user type in login credentials , if user get a phone call , i need to persist the data he typed in the text fields and stay connected to the network instead of getting crashed.. How can i do this. This is my first app. thank you..
Use saveinstancestate and restore instance state
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("photo_index", mCurrentPhotoIndex);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
mCurrentPhotoIndex = savedInstanceState.getInt("photo_index");
showPhoto(mCurrentPhotoIndex);
super.onRestoreInstanceState(savedInstanceState);
}
When my activity's (tab activity with two tabs) orientation is changed, the content of the tabs, which is another activity with a listview of items(with checkboxes), GOES BLANK. I have used android:configChanges="screenSize|orientation" in the manifest file, so that I dont want the checkboxes to be cleared(or recreated) on orientation change.
Could anyone please help me with this issue?
In order to save the state of View's within activities in Android you need to implement the onSaveInstanceState(Bundle outState) and onRestoreInstanceState(Bundle savedInstanceState) methods. See the Android Developer Guide for more on these methods.
onSaveInstanceState(Bundle outState) is called when the activity is destroyed on configuration change (change in orientation). You can add data to the bundle in this method and then retrieve it when the activity is restarted using onRestoreInstanceState(Bundle savedInstanceState).
For example:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Read values from the "savedInstanceState" bundle and put them back into the corresponding textviews
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the values you need from your textviews into the outState object
}
For more details on how to save data into bundles see the Android Developer Guide. This also explains the difference between restoring state using onCreate(Bundle savedInstanceState) and onRestoreInstanceState(Bundle savedInstanceState).
I have seen a few similar questions about onSaveInstanceState not getting called for Fragments, but in my case Fragments work fine, it's the main FragmentActivity that's having trouble.
The relevant code looks fairly simple:
public class MyFActivity extends FragmentActivity implements ActionBar.TabListener {
String[] allValues; // data to save
#Override
protected void onSaveInstanceState (Bundle outState) {
Log.d("putting it!", allValues.toString());
outState.putStringArray("allValues", allValues);
super.onSaveInstanceState(outState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
allValues = savedInstanceState.getStringArray("allValues");
Log.d("getting it!", allValues.toString());
}
}
}
When pausing the activity (using the back button), the onSaveInstanceState is never called, and consequently, savedInstanceState is always null within the onCreate method upon resuming the app. I tried adding a block like this:
#Override
public void onPause() {
super.onPause();
onSaveInstanceState(new Bundle());
}
which was suggested in https://stackoverflow.com/a/14195202/362657 but while onSaveInstanceState then gets called, savedInstanceState remains null within onCreate method. What am I missing?
The issue here is that you are misunderstanding how onSaveInstanceState works. It is designed to save the state of the Activity/Fragment in the case that the OS needs to destroy it for memory reasons or configuration changes. This state is then passed back in onCreate when the Activity/Fragment is returned to / restarted.
In a Fragment, all of their lifecycle callbacks are directly tied to their parent Activity. So onSaveInstanceState gets called on the Fragment when its parent Activity has onSaveInstanceState called.
When pausing the activity (using the back button), the onSaveInstanceState is never called, and consequently, savedInstanceState is always null within the onCreate method upon resuming the app.
When pressing back, the user is destroying the Activity, and therefore its children Fragments, so there is no reason to call onSaveInstanceState, since the instance is being destroyed. When you reopen the Activity, it's a brand new instance, with no saved state, so the Bundle passed in onCreate is null. This is behaving exactly as designed. However, try rotating the device or hitting the home button, then you will see the Activity and its children Fragments have onSaveInstanceState called, and passed back in onCreate when returned to.
The hack you added, directly calling onSaveInstanceState(new Bundle()); inside of onPause, is a very bad practice, as you should never call the lifecycle callbacks directly. Doing so can put your app into illegal states.
If what you really want is for your data to persist beyond an instance of your app, I suggest you look into using SharedPreferences or databases for more advanced data. You can then save your persistent data in onPause() or whenever it changes.
In an update to the accepted answer:
A fragment's onSaveInstanceState may be called if you are using a ViewPager with a FragmentStatePagerAdapter (rather than FragmentPagerAdapter)
FragmentStatePagerAdapter
This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.
And don't forget:
When using FragmentPagerAdapter the host ViewPager must have a valid ID set.
Not an accurate answer to the question, but may help someone's day.
In my case, I called
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
}
I replaced the above code as below and things worked
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
}
I make a login form with dynamic field validation. I have 3 fields username, email & password & all of these field are required. When field length = 0, I set error
editText.setError( getText(R.string.cannot_be_blank) );
and this code works fine, but when I change the orientation, all the errors disappear
How to save error state?
Thanks.
When the orientation is changed the framework will recreate the Activity by calling onCreate(Bundle savedInstanceState). Before the switch in orientation the onSaveInstanceState(Bundle outState) method will be called if it is overridden in your Activity.
You can save the state of your errors in the Bundle passed into the onSaveInstanceState method. This bundle is passed to your onCreate() method as the savedInstanceState Bundle.
Therefore you need to override the onSaveInstanceState method in your Activity as follows (saving the state of your errors):
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("errorOccurred", errorState);
super.onSaveInstanceState(outState);
}
Then in your onCreate method check if the savedInstateState Bundle is null or not. If not, you can retrieve the values out of it with the following code:
boolean errorOccurred = false;
if (savedInstanceState != null) {
errorOccurred = savedInstanceState.getBoolean("errorOccurred");
}
When the orientation is changed the Android framework destroys the Activity and then creates a new one for the new orientation. So all your state is lost.
Use SharedPreferences to store and restore your state and TextEdit values.
What happens when you turn the device is that your Activity runs through its lifecycle in order to deal with the fact that the layout must change from portrait to landscape.
You should take a look at the developer docs on how to Handle Runtime Changes.