Any activity can be killed under certain circumstances (e.g. "Other applications need memory"). After this, onCreate is called again on the activity.
The documentation says that in this case the "process is killed". Does this mean that the whole Activity instance is gc'ed and constructed again or only the GUI parts?
Given:
public class MyActivity extends Activity
{
private SomeClass someProperty = null;
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
if (someProperty == null) someProperty = new SomeClass ();
Log.d ("X", someProperty.toString () );
}
}
Will someProperty be null after the activity is killed and comes again to front, or will someProperty still be the same?
I am asking this, as it is hard to emulate the condition "Other applications need memory".
If you do nothing in onSaveInstanceState() method, it will be null. You might find some infomation useful reading this Android developer guide about activity lifecycle.
If you want the someProperty to be saved when the Activity is not destroyed normally(i.e., the user press the BACK button or the app calls finish() ), you can override the onSavedInstanceState() method and save whatever you want. There is a more explicit example in the tutorial linked above.
Also, there is another article and yet another article that explain the lifecycle of activity quite clear.
Hope helpful.
EDIT:
About when the onSavedInstanceState() will not be called(i.e. "destroy normally", which might be a confusing expression), this article says and I quote:
If the user interacts with an activity and presses the Back button or if the finish() method of an activity is called, the activity is removed from the current activity stack and recycled. In this case there is no instance state to save and the onSaveInstanceState() method is not called.
If the user interacts with an activity and presses the Home button, the activity instance state must be saved. The onSaveInstanceState() method is called. If the user restarts the application it will resume or restart the last running activity. If it restarts the activity it provides the bundle with the save data to the onRestoreInstanceState() and onCreate() methods.
Related
Basically what I need is to recreate one Activity each time I call startActivity() moving the instance to the front and not destroy the other activities.
For instance, if I have in the activity stack
A->B->C->D
and from D I want to open B, the flag I currently use is FLAG_ACTIVITY_REORDER_TO_FRONT which leave the Activity stack in this state: A->C->D->B. That order in the activity stack is perfect, however, with that flag the Activity is not recreated and onNewIntent() is called.
Because the complexity of the Activity I do not want to refactor a lot of things, what I want is to recreate B from scratch (onCreate() has to be called) instead of execute my logic in onNewIntent() method. The activity stack should have the same state as if I use FLAG_ACTIVITY_REORDER_TO_FRONT. Any idea? Your help will be much appreciated. :)
If all of your work happens in onCreate() and you want the same stuff to work within onNewIntent(), then you could do potentially get away with a simple re-factor. Where all your code is in the setupActivity() call.
public void onCreate (Bundle savedInstanceStateF)
{
super.onCreate (savedInstanceStateF);
setupActivity();
}
public void onNewIntent(Intent intentF)
{
super.onNewIntent(intentF);
setupActivity();
}
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.
Sorry for my incomprehension, but I am new in the android development.
I have an application with activity A and activity B in it, and I go from activity A to activity B. When I left activity A, the onSaveInstanceState method was called, but when I went back to activity A (from activity B in the same application), the bundle in the onCreate method was null.
What can I do, to save the activity A's previous state? I only want to store the data for the application lifetime.
Can someone help me with this?
Here is my code for Activity A:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
{
Log.v("Main", savedInstanceState.getString("test"));
}
else
{
Log.v("Main", "old instance");
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
Log.v("Main", "save instance");
savedInstanceState.putString("test", "my test string");
super.onSaveInstanceState(savedInstanceState);
}
public void buttonClick(View view)
{
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
}
Here is my code for Activity B, when I press a button to go back to activity A:
public void onBack(View view)
{
NavUtils.navigateUpFromSameTask(this);
}
To answer your question, have a look at the android doc: https://developer.android.com/reference/android/app/Activity.html#onRestoreInstanceState(android.os.Bundle)
It says that onRestoreInstanceState is called after onStart() method in the activity lifecycle.
Saving and restoring state is meant to save the current temporary data that is obsolete when user exits the application.
When you minimize or leave the Activity by opening next one it might be killed by the system due to lack of resources and restarted with savedInstanceState when you get back to it. So use onSaveInstanceState() only for saving minimize-restore session data or data that should be preserved on rotation.
So if you start a new Activity in front and get back to the previous one (what you are trying to do), the Activity A might not be killed (just stopped) and restarted without going being destroyed. You can force killing it and restoring by checking Don't keep activities in developer options menu.
If you call finish() or remove the Activity from recent task list the savedInstanceState will not be passed to onCreate() since the task was cleared.
If the value must be persistent consider using SharedPreferences.
This happens because you are navigating the hard way. If you used the phone's default back button navigation, your onCreate would get the bundle passed in.
To circumvent this issue, I suggest you save your state to shared preferences as well as a back up. When the bundle is null, restore it from the shared preferences.
reference
onSaveInstanceState
... onPause()-> onSaveInstanceState() -> onStop() -> onDestory()
onRestoreInstanceState
onCreate()-> onStart()-> onRestoreInstanceState()-> onPostCreate(Bundle) ...
Or You can use LiveData. Save the states in it and observe.If the device rotates it'll update the views accordingly.
After onStart() which is after onCreate()
I used in this case a flag and SharedPreferences. This should work, and when you change the screen orientation.
Suppose I have two activities, activity1 and activity2.
I want to navigate from activity1 to activity2, get some info from activity2 and insert back it to activity1 and also I don't want to lose activity1 previous state as I left.
how can I save its state ?
what you are describing is the perfect classic reason to use the Activity.startActivityForResult() method.
this what google wrote in this method documentation:
Launch an activity for which you would like a result when it finished. When this activity exits, your onActivityResult() method will be called with the given requestCode
so what you should do is: from your activity1 start activity for result, and from activity2 use the setResult(int resultCode, Intent data) method with the data you want your activity1 to get back, and call finish() (it will get back to onActivityResult() in the same state activity1 was before..).
Override onSaveInstanceState(Bundle) in activity1 to save whatever data you want then override onRestoreInstanceState(Bundle) in the same activity to get the values back. Using Bundle, you can store pretty much any data that you want. I'd recommend something like this:
public class MainActivity extends Activity {
...
public static final String DATA1_KEY = "data1";
private boolean value1;
...
#Override
protected void onSaveInstanceState (Bundle outState) {
outState.putBoolean(DATA1_KEY, value1);
}
#Override
protected void onRestoreInstanceState (Bundle savedInstanceState) {
value1 = savedInstanceState.getBoolean(DATA1_KEY);
}
}
You should override onSaveInstanceState(Bundle savedInstanceState)
Please check this answer for example code
Or use SharedPreferences. Check this code
If you want to keep your data alive only at runtime, the consider using static members. Then you can access and manipulate these members from any activites. for example:
public class FirstActivity extends Activity
{
public static String data = null;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
data = "This is a test!";
}
}
From your second activity you can access these static variables like
public class SecondActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
if(FirstActivity.data!=null)
{
//You can use it:
System.out.println(FirstActivity.data);
}
}
}
Of course you can add getter/setter functions to make it safer and more elegant.
If you want to store them for a longer time, the please consider using:
SharedPreferences
SQLite
or store your data in an online database.
The user performs an action in your app that starts a new activity. The current activity is stopped when the second activity is created. If the user then presses the Back button, the first activity is restarted.
When your activity is stopped, the Activity object is kept resident in memory and is recalled when the activity resumes. You don’t need to re-initialize components that were created during any of the callback methods leading up to the Resumed state. The system also keeps track of the current state for each View in the layout, so if the user entered text into an EditText widget, that content is retained so you don't need to save and restore it.
Note: Even if the system destroys your activity while it's stopped, it still retains the state of the View objects (such as text in an EditText) in a Bundle (a blob of key-value pairs) and restores them if the user navigates back to the same instance of the activity.
CommonsWare here says:
When user "press the BACK button", then the Bundle from
onSaveInstanceState() (if any) is discarded, as the user has indicated
they are finished with the activity. The onSaveInstanceState() Bundle
is used in cases where the user has not said they are finished with
the activity (e.g., they accepted an incoming phone call) yet Android
elects to destroy the activity to free up RAM.
And documentation says:
Note that it is important to save persistent data in onPause() instead
of onSaveInstanceState(Bundle) because the later is not part of the
lifecycle callbacks, so will not be called in every situation as
described in its documentation.
In other words, put your save/restore code for non View objects in onPause() and onResume() instead of onSaveInstanceState(Bundle) and onRestoreInstanceState(Bundle).Finally I guess that you don't need to save any state if you only have View objects and if you have any other states you can use preferences,file or sqlite to save them in onPause() and retreive them in onResume().
You can see more details in these pages:
Stopping and Restarting an Activity
Saving Activity state in Android
Android wont save the current state of an activity
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!