Restore values on screen rotation - android

I have created several TextViews programmatically. When screen rotates I loose all added text views and their text values. What is the best way to save them and restore after rotation. I am using a tablelayout and adding rows each row has four textviews. I did not want to prevent device rotation.

You should use onSaveInstanceState to save your state, and then recreate it in onCreate. This works for both Activities and Fragments, but I believe the visibility on the methods is a bit different (they're public for Fragments).
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text1", text1.getText().toString());
// do this for each of your text views
// You might consider using Bundle.putStringArray() instead
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize all your visual fields
if (savedInstanceState != null) {
text1.setText(savedInstanceState.getString("text1", ""));
// do this for each of your text views
}
}
Note that this is better than using onRetainNonConfigurationInstance; that method is used to actually keep objects around across rotations (e.g. Bitmaps), however you want to just store the strings, and thus using a Bundle is preferred. Also, onRetainNonConfigurationInstance isn't supported by Fragments; it's been replaced with setRetainInstance, and you don't want to use that for the same reason.

You need to persist the state across Device Rotation. As your view gets created dynamically, you need to store all this information in a 'Model' appropriate for your application. Android developer website has more info.
"To retain an object during a runtime configuration change:
Override the onRetainNonConfigurationInstance() method to return the object you would like to retain.
When your activity is created again, call getLastNonConfigurationInstance() to recover your object."
Take a look here: http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject

Related

Is it ok to serialize a List of Views?

I want to send a list of views inside a bundle, so the activity can be reconstructed using the values from before it get destroyed, for example when the user rotate the device, but I start getting errors on retrieving the views.. Is that okay to use that approach?
PS. I didn't post code because I think that would be unnecessary, if you guys think it would be nice to read the code, please request and I will update the question.
You seem to have the right idea but incorrect implementation. Use onSaveInstanceState, and if you want you can put things into your Bundle. Lets take a more practical example, such as a string value.
private TextView mTextView;
private static final String KEY_TEXT_VALUE = "keyTextValue";
#Override
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_TEXT_VALUE, mTextView.getText());
}
Whenever Android destroys and recreates your Activity for orientation change it calls onSaveInstanceState() before destroying and calls onCreate() after creating. So if you want, you can retrieve the saved information in onCreate() like this,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = (TextView) findViewById(R.id.main);
if (savedInstanceState != null) {
String savedText = savedInstanceState.getString(KEY_TEXT_VALUE);
// do something with savedText
}
}
If you have a lot of data you may consider creating some sort of cache, SQLite would be sufficient enough.
It is ok to serialize the data the views need to redraw themselves and restore their state if the size of your list isn't really big. You should not be serializing the views itself.
When you serialize too much data, you will know as your app will crash :)
When there is too much data, use SQL instead or just tell your activity or fragment not to destroy itself and avoid this hassle altogether.
If you want to save the state of your Activity, save it into onSaveInstanceState(Bundle savedInstanceState) method, this method belongs to Activity class. For example:
savedInstanceState.putString(USER_NAME, myEditText.getText.toString());
In onCreate() method you can retrieve your data this way:
if (savedInstanceState != null) {
// restore as many values from views as you need
mUserName = savedInstanceState.getString(USER_NAME);
}
You may also consider using this line of code.
android:configChanges="orientation|keyboardHidden"
This will prevent your app from reseting your data when orientation changes.
Also see this tutorial.

creating a Parcelable which will be used inside the same activity

I've imported some JSON data and fetched it into a custom arrayList. The arraylist looks like this:
ArrayList<HashMap<String, String>> postList;
It all works fine, but if the orientation changes the whole JSON parse/fetch process will start over again. That's why I like to store my custom ArrayList.
I have found a lot of information about (how to use) the Parcelable interface, but they all cover sending data from activity A to B.
Can somebody please provide an example about how to use a Parcelable inside the same activity? Thanks in advance!
You should search online for onSaveInstanceState, it's a callback which is defined inside Activity class.
It works in the same way when you need to pass data between activites
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
}
Inside outState you will use normal Bundle methods to pass Strings, Integers and Parcelable values (putParcelableArrayList/putParcelable/putParcelableArray).
When the screen rotate or something happens (activity got destroyed etc.), this method could be called and when the activity gets recreated the bundle you used here will be passed to onCreate inside the savedInstanceState argument (the only argument of onCreate, Bundle).
Here inside onCreate you check if (savedInstanceState != null) to be sure you have a saved state, if it's true you use savedInstanceState.getParcelableArrayList (or something else, depends on what you want to get) to read back the list.
if (savedInstanceState != null)
{
ArrayList<Parcelable> parcelableArrayList = savedInstanceState.getParcelableArrayList("key");
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelableArray(myParcelableList);
}
It all works fine, but if the orientation changes the whole JSON parse/fetch process will start over again. That's why I like to store my custom ArrayList.
You mentioned that your orientation causes the whole process to restart in your Activity. Are you running the json... etc in your onCreate method? If that's the case, orientation changes cause onCreate to be called.
You can prevent onCreate from being called by modifying your AndroidManifest.xml to handle your own orientation changes for the current activity (look for the android:configChanges):
<activity
android:name="your.activity.package.andclass"
android:configChanges="orientation|screenSize">
<!-- etc -->
You might need to manually handle config changes for certain events, but I've never found it necessary.

Fragment state lost when device left idle

Fragment losing state and shows an empty UI if left idle for 20 minutes. I'm using FragmentStatePagerAdapter and I have tried calling the notifyDataSetChanged in onStart() of my FragmentActivity.
Kindly help me how to save the object and state of my fragment and reuse it on reload of the app.
Android can kill your app if needed, you need to use onSaveInstanceState to keep your state in this cases. (Remember: Save important data in onPause!)
onSaveInstanceState exists in Activity and Fragments and is used in the same way like an activity
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("integer", anInteger);
}
Now in onCreate, onCreateView or onActivityCreated you have this argument BundlesavedInstanceState which corrisponds to the bundle saved. (Check if it's null too.)
If not enought maybe Android killed your FragmentManager too, so you need to override onSaveInstanceState and onRetoreInstanceState in your Activity and restore the fragment.
Maybe this answer could help you about the last thing i said: Using onSaveInstanceState with fragments in backstack?
A Fragment's life-cycle is closely tied to the Activity's lifecycle. This means, when your Activity goes idle; it will kill off any contained Fragments. To store Fragments you could always retain them in concordance with the Fragment API. This means you will generally be using the Fragment in a background. However the best way to keep a from being destroyed or lost from an Activity's end would be to store relevant information in a custom object and then to recreate the Fragment when the Activity is resumed.
For instance; I could have a custom object that would store relevent UI values for my Fragment and when my Activity either idles or changes I would save those relevant values to my custom object that I created. Then, when either a new Activity is created; or my old Activity is resumed; I would retrieve those values and put them back into my Fragment's UI. Hoped this helped :)
In case android needs memory, it kills the running apps. So you must save the objects using
public void onSaveInstanceState(Bundle savedState) {}
Note that savedState must be serializable.
You must call notifyDataSetChanged() in onResume(), because it ensures that it is called when the activity resumes.
For a detailed answer, please post your code.
Hard to answer without your code.
However I can say that the state is usually saved by the savedInstanceState
Usually in the onActivityCreated you have something like the following. In the example I give I save a boolean of either text was entered or not.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mHasText = savedInstanceState.getBoolean(HAS_TEXT_TAG);
} else {
// do something
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(HAS_TEXT_TAG, mHasText);
}
it's just an example as without your code it's difficult to anwer

Explain GoogleApi savedInstanceState

In the Google Api Example Code they have a very simple example on saving the state. I need this in order to deal with screen rotation.
My problem is that I do not understand where the methods getSavedText() and setSaveText() get called from. I put the debugger on them but it never gets triggered. The whole thing just works by "magic". What other things can I save? where do I find documentation explaining the magic
public class SaveState extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_save_state);
((TextView)findViewById(R.id.msg)).setText(R.string.hello_world);
}
CharSequence getSavedText() {
return ((EditText)findViewById(R.id.saved)).getText();
}
void setSavedText(CharSequence text) {
((EditText)findViewById(R.id.saved)).setText(text);
}
}
Link
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/SaveRestoreState.html
Alternate link
http://goo.gl/6TJy5
This Api Demo sample is bad one because it is confusing that you are expecting it will override onSaveInstanceState() method than use persisted state in onCreate() or onRestoreInstanceState() when you read the documentation, but it does not.
Firstly getSavedText() and setSavedText() methods are not used in this Save & Restore State activity. They are used/called in LocalSample Instrumentation example.
Forget these two methods you can erase them. Let's come to how this sample works; on background Android calls onRestoreInstanceState() and make all UI views persist their state to Bundle parameter of the method. Please debug the code and after rotating screen inspect savedInstanceState parameter in onCreate() method of this sample. You will see before rotation text of R.id.saved EditText in that Bundle. Main trick is that why one of EditText is saving its state and the other is not is because of freezesText attribute of EditText. freezesText attribute makes EditText/TextView save its state in onSaveInstanceState method. Please look here for more information about freezesText.
delete android:freezesText="true" or make it false from save_restore_state.xml or override onRestoreInstanceState method and do not call super.onRestoreInstanceState() and observe that it is loosing its state after rotation (configuration changes).
Note: You do not have to override onRestoreInstanceState method for this sample but for other requirements to save internal state of the Activity you have to.

How to save the state of Spinner in onSaveInstanceState when changing the orientation in android

I want to save the state (ie. content) of spinner tied to an Adapter when chnaging the orientation. I am using onSaveInstanceState(Bundle savedInstanceState) and onRestoreInstanceState(Bundle savedInstanceState) method .
Will u give the step by step process how to save the content?
Thanx
Here is an excellent example of how to do this (look at onPause & onResume), Spinner Example. I would strongly suggest also adding activity testing (aka unit testing) to make sure you restore all your states around the lifecycles. unit test example.

Categories

Resources