I am developing an application in which i am overriding the back button. I created a check box. On click of which i am calling intent for:
startActivityforResult();
And also maintaining the state of activity as :
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean("checkbox", checkbox.isChecked());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
checkbox_state = savedInstanceState.getBoolean("checkbox");
}
which run fine and the state is maintained.
Means i am entering value in edit text. and on check box click calling new activity for result and while return on first activity the state is maintain.
Now but from second activity if i click on device back button the state is not maintained.
So what should i do to maintain the state on back button. I searched but not found satisfied solution. Please suggest me.
When You start the new Activity then the current Activity gets hidden and new Activity is placed on top of the stack. Now if you press the back button on the new Activity then the first activity should come up in its current state (If it wasn't destroyed, calling finish()) where it was left i.e. if the check box was checked then it should remain checked. You don't need to save the activity state unless the orientation is changed or the activity is destroyed.
Are you sure you are not doing any thing in the onActivityResult or onResume() method which effects the state of the check box? I would recommend to first comment out all the code in both the methods and see if your check box retains the state. Also can you also make sure that the code itself doesn't uncheck the checkbox before starting the new Activity?
Now but from second activity if i click on device back button the state is not maintained.
onSaveInstanceState() is mostly used for configuration changes (e.g., rotating the screen).
So what should i do to maintain the state on back button
Most likely, there is no "state" that needs to be "maintained", outside of your data model. Your activity needs to update its data model: files, database, preferences, ContentProvider, some singleton that is your in-memory data model manager, whatever.
Related
Suppose I have activities A, B, C, D, E.
when I open application with activity A and switch to activity B and further to activity C. Suppose, somehow B gets destroyed by system. and when I press back button, I came out of app. What I really wanted was to be able to go to B if it exists otherwise A (landing page). In normal cases it's working smoothly but it's some cases where I have to interact with other apps/interfaces for eg. open url in browser. After sometime if I go back to app, I see latest page as it is but when I press back button app exits.
I have searched for solutions but couldn't find one so posting it as a question.
I know the idea of passing extra in intent and starting new intent on back press but these would not work in some cases or requires creating a backstack handler of own.
There is no guarantee that your activities will stay in memory and this is an intentional behaviour.
Your option is use to onRestoreInstanceState and onSaveInstanceState so that user do not lose critical data.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Get data
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Save data
super.onSaveInstanceState(outState);
}
One way which I have used in the past to validate activity state is to add e.g. a boolean attribute in your activity, set this true when activity starts, if your activity is destroyed after some time this will be false. Check state by overriding the activities onBackPressed method?
e.g.
onBackPressed(){
if status{
/*activity live*/
}
else{
/*activity destroyed/*
}
}
This might work If I understand you issue correctly.
This app have 2 Activities: MainActivity and SettingActivity (using an intent to send value).
...MainActivity :
String set="1";
public void onCreate(Bundle instant) {
super.onCreate(instant);
setContentView(R.layout.camera);
...when my app is running, i change value of set : set="2" by SettingActivity , and it work correctly in MainActivity.
Then, i press the Home button, and start this app again , it work with set="1" , in layout camera.xml ;
And when i press the Back button : after a little change in screen, it work with set="2" with layout camera.xml .
Why it have 2 layout when i run it again after press Home Button. And why i have to Press the Back button to get the exact value of set in that time.
i have tried to override onSaveInstanceState (Bundle instant). But it still the same.
Have you try to look at this answer first
Saving Android Activity state using Save Instance State
When you press the Home button and you return to your application it can be restarted and so the set variable come back to its original value.
To save your variable state you have to write
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putString("set", set);
}
Then you can recover the values like this:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
String myString = savedInstanceState.getString("set");
}
Moreover, why are you using a String to contain integer values?
Hope this help
String set="1"; // intial global value for everyone
"when my app is running, i change value of set : set="2" by SettingActivity"
by that time MainActivity is paused, you come back, now it is resumed, you press homebutton, then it is paused and stoped, you call it one more time, guess is the os created another activity of it, and started the whole process, you press the back button you kill the newly created class, then the old one pops up, get it?
you can always play aroundsingletask or singleTop but why it gave two layouts well it depends on how you called your class or your activity..probably with different intents..
basically my app has 2 activities.Say "A" and "B"
.
A launches B.
Activity B plays music and also has a notification.
Case 1:when the view is still on activity B` i press home button and then i click on the the notification, activity B is opened with its view intact and with its music playing (because in the manifest i am using android:launchMode= "singleTop" and hence another instance of the activity is not created) this part is as desired......
but
Case 2:when the view is on activity B and i press back button ,activity A appears and then i click on the the notification, activity B is opened with the view lost and music also stops(not desired)......i am making a guess that it happens because when i press the back button the activity is destroyed ,so i have to progamatically restore its view right??so to restore its view i override two methods .....
#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("boolMusicPlaying", boolMusicPlaying);
savedInstanceState.putInt("swapnumber", swapnumber);
savedInstanceState.putString("seekbarprogress", progress2);
savedInstanceState.putInt("position.seekbar",seekbar.getProgress());
savedInstanceState.putString("seekmaxString", max2);
savedInstanceState.putInt("seekmaxInt",seekMax);
savedInstanceState.putParcelableArrayList("songfetails",songdetails);
super.onSaveInstanceState(savedInstanceState);
}
//make a note ....even if i don't override onDestroy() and don't call on SaveInstanceState explicitly, then too i am not getting any desired effect.......
#Override
public void onDestroy()
{ Bundle savedState = new Bundle();
onSaveInstanceState(savedState);//because of this line....the app is crashing......
super.onDestroy();
}
but it didn't help.....
and in on create i am putting a check if saved instances is null or not....create view accordingly...(i.e from saved instances or from fresh) but it didn't help...
also this line is giving a crash ...onSaveInstanceState(savedState);
even if i don't override ondestroy() and kill the app manually from task killer,and then try to open activity B,then too the saved instances thing should work right,because the method OnSaveInstanceState will be automatically called then,right???please help
Basically if you have pressed a back button,restoration of activity should be done using shared preferences/or a database but if you haven't pressed the back button and then you want to restore the state of the activity (because the activity was destroyed by the system ) then the bundle savedinstances can be used ...
From Android documentation:
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed. However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
To fix second problem you must restore data form some other source (service that plays music, restore info from application context or singleton, etc.)
For more info check this.
I have an activity A which shows different screens. I chose to show multiple views in the same activity, by using setContentView.
When you launch the app, Activity A shows the default screen. You then choose an option and the activity shows you another set of options by setting setContentView to another view. This new view now takes you to a new activity(Activity B) when you click it, and Activity A calls finish()
If I now end Activity B, by calling finish() on it, I am being taken back to Activity A, and it calls it's onCreate(). I can't figure out what's wrong here. Why would an activity recreate itself when Activity B never called an intent for Activity A?
view.findViewById(R.id.quit).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
The issue is most likely because the purpose of onCreate() is to create the Activity's state as it was when it left. You can't under any circumstances assume that an Activity will maintain its state once the user leaves it. Views are memory intensive, and the system is going to dump it as soon as it needs more memory for the current top Activity. If this happens then the system must recreate the Activity to its original state before the system dumped it.
You can save states via the onSaveInstanceState(Bundle) method. The bundle that's passed in to onCreate is the same bundle you set in onSaveInstanceState(), so all parameters will be there. Then you can rebuild just as it was.
The books I have are abysmal at explaining how to work with the lifecycle, there's a lot I'm missing that I'm hoping somebody can fill in.
My app structure is that when it's first started, it starts an activity full of legalbabble that the user has to accept. When he says 'ok', I start my main activity and then I call finish like this:
public void onClick(View view) { //as a result of "I accept"
Intent mainIntent = new Intent(mParent, EtMain.class);
startActivity(mainIntent); // Start the main program
finish();
}
Then in EtMain in the onCreate method, I've got some tabs and I instantiate some classes:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTabHost = (TabHost)findViewById(android.R.id.tabhost);
SetupTabs.setMyTabs(mTabHost, this);
mComData = new ComFields(this); // Create the objects
mDepWx = new WxFields(this, DepArr.Departure);
mArrWx = new WxFields(this, DepArr.Arrival);
mDepVs = new DepFields(this);
mArrVs = new ArrFields(this);
mTabHost.setOnTabChangedListener(new OnTabChangeListener(){
}
Questions:
The 'finish' in the first fragment should terminate the legalbabble activity so it'll never be restarted, right? And the EtMain one will remain forever (until killed externally), even if my app gets pushed to the background, right?
The way it is now, when EtMain gets pushed and later brought to the foreground (by tapping on the icon), it goes through the legalbabble screen as though it's a complete start - that's what I'd like to prevent - going thru the legalbabble screen again.
It would seem that I'd want to override onRestart in the second code fragment and put something in there to restart the app, right? That's the part I'm unclear about.
My question then is what needs to be done in onRestart. Do I have to recreate all the tabs and data in the tabs and all my object instantiations? Or is the memory state of the app saved someplace and then is restored back to the state that it was in before something else was brought to the foreground in which case not much needs to be done because all the objects and listeners will still be there?
Yes after the first activity has ended you shouldn't have to view that activity again. You could also write to the shared preferences that the user has previously seen legal info.
If you're UI object creation is in the onCreate method, this should only be called once. Pausing or resuming will not call the onCreate method again.
Unless you explicitly remove your objects and tabChangedListeners in the onPause method, you should not have to touch them in the onRestart method.
Correct, the state of the app is saved automatically. You shouldn't have to touch the onRestart method.
Hope this helps!
I think the problem is that the launch activity in your manifest is the legalbabble activity, so when you click on the icon, the system launches another one. A better architecture would be to launch the legalbabble activity it from your EtMain activity in the onCreate method of the latter, using startActivityForResult. From the docs:
As a special case, if you call startActivityForResult() with a requestCode >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your activity, then your window will not be displayed until a result is returned back from the started activity.
When you get the result in onActivityResult, you can call finish() if the legal stuff was declined; otherwise everything will proceed normally.
This avoids the problem that the launch activity defined in your manifest finishes when the legal stuff is accepted.
EtMain will not remain forever, if the user backs out (by pressing the BACK key) the Activity will be finished (onPause, then onStop, then onDestroy will be called).
In general you can ignore onRestore until you are doing something complicated.
Once the user has exited your application and re-enters (or presses the icon on the Homescreen), onCreate (followed by onStart and onResume) will be called for your first activity, so you do not need any logic in onRestart, your code in onCreate will do the setting up for you as it did the first time. Because of this your legal babble will appear again when the user starts the app after exiting unless you store a preference (in SharedPreferences or a database or file) to indicate you have already displayed it - in which case finish it straight away and start the main activity.
onRestart is only called when the application goes from the stopped state (onStop has been called but not onDestroy) to the started state (onStart is called but onResume has not yet).
For saving data - some components save their state automatically (e.g. EditTexts remember the text in them, TabHosts remember the currently selected tab etc). Some components will not. If you wish to save extra data then make use of onSaveInstanceState and onRestoreInstanceState. You should only use these methods to restore the state of your application or temporary data, not important things, e.g. the id of the resource what the user was looking at, what zoom level they were at etc. For things like contacts or actual data you should commit these changes to a database, SharedPreferences or other permanent storage (e.g. file) when onPause is called.
I recommend taking a look at the Android Activity lifecycle if you are confused. Or ask more questions!