TextView.onRestoreInstanceState() doesn't work - android

My app needs to be able to dynamically create TextViews, so I need to be able to restore them if my app is ever GCed or switches orientations. The problem is I can't figure out how to restore the state of my TextViews. Saving their states with TextView.onSaveInstanceState() seems to work just fine, but when the Parcelable is passed to onRestoreInstanceState(), nothing happens and the resulting view is just blank. This is a short example which doesn't work:
public class MainActivity extends AppCompatActivity {
TextView v;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_main);
ViewGroup main = (ViewGroup) findViewById(R.id.main);
v = new TextView(this);
main.addView(v);
if (state == null) {
v.setText("A simple message.");
} else {
v.onRestoreInstanceState(state.getParcelable("message"));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("message", v.onSaveInstanceState());
}
}
I have checked the value of state.getParcelable("message") in the debugger and it definitely has the required information. onRestoreInstanceState() just isn't using it. Any help at all would be appreciated.
EDIT: I screwed up with the debugger. The information was actually never written to the bundle. TextView.onSaveInstanceState() had returned an empty Parcelable. That was the real problem.

I figured it out. It the problem was with TextView.onSaveInstanceState()—not TextView.onRestoreInstanceState(). TextView.onSaveInstaceState() only saves the state if you explicitly ask it to by calling TextView.setFreezesText(true) first. SURPRISE! Thank you, Google. Also note that onRestoreInstanceState() doesn't restore the FreezesText property. Oh, Google. You're just so zany. What'll we do with you?

Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null:
Save Your Activity State:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Restore Your Activity State:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
}
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);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Related

state of app after 2 rotations

i have been through this documentation regarding the topic save a state before the foreground activity will be destroyed...
and everything works really good now (after a device rotation), but when i rotate my device again after a rotation, i will loose my data again :(
here is my code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MainActivity activity = this;
activity.setTitle("Cow Counter");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText(Integer.toString(cowQnty));
}
// invoked when the activity may be temporarily destroyed, save the instance state here
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("qnty", cowQnty);
}
// How we retrieve the data after app crash...
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//cowQnty = savedInstanceState.getInt("qnty");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}
I think the solution will be maybe to implement a check if an instance state was already restored before...
i have tried then this here:
if(savedInstanceState.getInt("qnty") != 0){
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}
buit then my inital part in my onCreate() method will write a zero in my result field
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText(Integer.toString(cowQnty));
Could anyone tell me if I am close to the solution?
You use a variable called cowQnty to store the value that is then saved in the bundle for your onSaveInstanceState as outState.putInt("qnty", cowQnty);, then when you restore it in onRestoreInstanceState you only set the TextView's value to the retrieved value and do not update the value for cowQnty.
How do you expect then to save an empty field again? There are two solutions to this;
Firstly, if cowQnty is not a sizeable amount and you do not mind using a tad of RAM, make cowQnty a static field and it will persist the data without needing to save it in a Bundle at all.
Secondly, just set cowQnty's value once again when you restore your state (why did you comment it out??), like so:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
cowQnty = savedInstanceState.getInt("qnty");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}

how to use onSavedInstance method to prevent data loss while changing to landscape mode

I am making a Sample of twitter integration ,i am fetching user information on click of button. Data is coming on screen it is working fine with portrait modeb but as i changed to landscape mode ,data loss.
how to solve this issue, i dont know how to use onSavedInstance method to solve this problem. please help
You need to override android default methods like onSaveInstanceState and onRestoreInstanceState check this example.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
//you can retrieve saved values from here
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);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
click here to find more about this

Why are my CheckBoxe's state never saved?

I have a few CheckBox elements inside one of my Fragments.
Every time I leave this Fragment it seems to nor save or restore the checked state of each one provided by the user.
In the FragmentList example you can find:
CheckBox check1;
boolean active;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("state1", check1.isChecked());
}
Which you can use later like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
check1.setChecked(savedInstanceState.getBoolean("state1"));
}
}
But somehow the CheckBox elements don`t save their state.
Is this the correct approach I should take?
Unless you're keeping your Fragment reference alive through the lifecycle of the application, it should be fine to save its state in onSaveInstanceState and restore it in onActivityCreated.
One important point, though, is also to save and restore that state in the Activity level by doing like:
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
// Restore the fragment's instance
mFragment = getSupportFragmentManager().getFragment(
savedInstanceState, "fragKey");
...
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the fragment's instance
getSupportFragmentManager().putFragment(outState, "fragKey", mContent);
}
Please check to see how your Activity is behaving in your scenario.

How to save and recreate android activities

I'm trying to teach myself some android programming and I'm unable to get my app to save and load a users progress.
Currently I initialise my variables level and score in my activity. Then call this from my onCreate method:
if (savedInstanceState != null) {
// Restore value of members from saved state
playersScore = savedInstanceState.getInt(STATE_SCORE);
level = savedInstanceState.getInt(STATE_LEVEL);
} else {
playersScore = 0;
level = 0;
}
and finally I have a method for saving a bundle:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt(STATE_SCORE, playersScore);
savedInstanceState.putInt(STATE_LEVEL, level);
super.onSaveInstanceState(savedInstanceState);
}
For some reason my bundle wont save, any ideas on what I'm missing?
From the docs:
Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.
Have you looked at:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
playersScore = savedInstanceState.getInt(STATE_SCORE);
level = savedInstanceState.getInt(STATE_LEVEL);
}
Also shouldn't:
savedInstanceState.putInt(STATE_SCORE, playersScore);
savedInstanceState.putInt(STATE_LEVEL, level);
be:
savedInstanceState.putInt("STATE_SCORE", playersScore);
savedInstanceState.putInt("STATE_LEVEL", level);
As putInt() requires a string and an int.

How to use onSavedInstanceState example please

I'm confused when it comes down to saving a state. So I know that onSaveInstanceState(Bundle) is called when the activity is about to be destroyed. But how do you store your information in it and bring it back to its original state in onCreate(Bundle savedInstanceState)? I don't understand how this bundle will restore information. It would be helpful if someone can provide an example.
The Dev guide doesn't do a good job of explaining this.
public class Conversation extends Activity {
private ProgressDialog progDialog;
int typeBar;
TextView text1;
EditText edit;
Button respond;
private String name;
private String textAtView;
private String savedName;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.dorothydialog);
text1 = (TextView)findViewById(R.id.dialog);
edit = (EditText)findViewById(R.id.repsond);
respond = (Button)findViewById(R.id.button01);
if(savedInstanceState != null){
savedInstanceState.get(savedName);
text1.setText(savedName);
}
else{
text1.setText("Hello! What is your name?");
respond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
name = edit.getText().toString();
text1.setText("Nice to meet you "+ name);
}
});
}
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString(savedName, name);
}
}
The Bundle is a container for all the information you want to save. You use the put* functions to insert data into it. Here's a short list (there are more) of put functions you can use to store data in the Bundle.
putString
putBoolean
putByte
putChar
putFloat
putLong
putShort
putParcelable (used for objects but they must implement Parcelable)
In your onCreate function, this Bundle is handed back to the program. The best way to check if the application is being reloaded, or started for the first time is:
if (savedInstanceState != null) {
// Then the application is being reloaded
}
To get the data back out, use the get* functions just like the put* functions. The data is stored as a name-value pair. This is like a hashmap. You provide a key and the value, then when you want the value back, you give the key and the function gets the value. Here's a short example.
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("message", "This is my message to be reloaded");
super.onSaveInstanceState(outState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String message = savedInstanceState.getString("message");
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
Your saved message will be toasted to the screen.
One major note that all new Android developers should know is that any information in Widgets (TextView, Buttons, etc.) will be persisted automatically by Android as long as you assign an ID to them. So that means most of the UI state is taken care of without issue. Only when you need to store other data does this become an issue.
From Android Docs:
The only work required by you is to
provide a unique ID (with the
android:id attribute) for each widget
you want to save its state. If a
widget does not have an ID, then it
cannot save its state
A good information: you don't need to check whether the Bundle object is null into the onCreate() method. Use the onRestoreInstanceState() method, which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null
Store information:
static final String PLAYER_SCORE = "playerScore";
static final String PLAYER_LEVEL = "playerLevel";
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(PLAYER_SCORE, mCurrentScore);
savedInstanceState.putInt(PLAYER_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
If you don't want to restore information in your onCreate-Method:
Here are the examples: Recreating an Activity
Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null
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(PLAYER_SCORE);
mCurrentLevel = savedInstanceState.getInt(PLAYER_LEVEL);
}
Basically onSaveInstanceState(Bundle outBundle) will give you a bundle.
When you look at the Bundle class, you will see that you can put lots of different stuff inside it. At the next call of onCreate(), you just get that Bundle back as an argument.
Then you can read your values again and restore your activity.
Lets say you have an activity with an EditText. The user wrote some text inside it.
After that the system calls your onSaveInstanceState().
You read the text from the EditText and write it into the Bundle via Bundle.putString("edit_text_value", theValue).
Now onCreate is called. You check if the supplied bundle is not null. If thats the case,
you can restore your value via Bundle.getString("edit_text_value") and put it back into your EditText.
This is for extra information.
Imagine this scenario
ActivityA launch ActivityB.
ActivityB launch a new ActivityAPrime by
Intent intent = new Intent(getApplicationContext(), ActivityA.class);
startActivity(intent);
ActivityAPrime has no relationship with ActivityA.
In this case the Bundle in ActivityAPrime.onCreate() will be null.
If ActivityA and ActivityAPrime should be the same activity instead of different activities,
ActivityB should call finish() than using startActivity().
If Data Is not Loaded From savedInstanceState use following code.
The problem is url call is not to complete fully so, check if data is loaded then to show the instanceState value.
//suppose data is not Loaded to savedInstanceState at 1st swipe
if (savedInstanceState == null && !mAlreadyLoaded){
mAlreadyLoaded = true;
GetStoryData();//Url Call
} else {
if (listArray != null) { //Data Array From JsonArray(ListArray)
System.out.println("LocalData " + listArray);
view.findViewById(R.id.progressBar).setVisibility(View.GONE);
}else{
GetStoryData();//Url Call
}
}

Categories

Resources