There are a bunch of other questions about this topic, but I have not been able to figure this issue out.
In the Android documentation (http://developer.android.com/training/basics/activity-lifecycle/recreating.html) it says:
By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object). So, if your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you.
So I tested this in the emulator by simply creating a view that contains a EditText-view. I then enter information into it and press the home button. When I reopen the app, the information is gone. Shouldnt this be persisted automatically or am I missing something?
Well you are partially wrong and partially right. You are wrong, because the quotation in grey is taken out of the context. I'll explain briefly, by making the correct quotations from the link you provided:
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.
Now, after that paragraph we have a clarification:
Caution: Your activity will be destroyed and recreated each time the
user rotates the screen. When the screen changes orientation, the
system destroys and recreates the foreground activity because the
screen configuration has changed and your activity might need to load
alternative resources (such as the layout).
Another one, several linew below is:
To save additional data about the activity state, you must override
the onSaveInstanceState() callback method. The system calls this
method when the user is leaving your activity and passes it the Bundle
object that will be saved in the event that your activity is destroyed
unexpectedly. If the system must recreate the activity instance later,
it passes the same Bundle object to both the onRestoreInstanceState()
and onCreate() methods.
This Bundle (Bundle savedInstanceState) is used, when the application accidentally crashes OR if the rotation of the screen is enabled (to name few), which is also destoying (then recreating) your foreground.
You can also take a look at the following section "Save Your Activity State", but I would recommend you this link here.
Related
Except being the first Activity upon the Start of the Application, is there anything else special about main activity?
From:https://developer.android.com/codelabs/android-training-create-an-activity#0
An app usually consists of multiple screens that are loosely bound to
each other. Each screen is an activity. Typically, one activity in an
app is specified as the "main" activity (MainActivity.java), which is
presented to the user when the app is launched. The main activity can
then start other activities to perform different actions.
From the quote above it seems to me that we have following hierarchy:
but then further is said:
Each time a new activity starts, the previous activity is stopped, but
the system preserves the activity in a stack (the "back stack"). When
a new activity starts, that new activity is pushed onto the back stack
and takes user focus. The back stack follows basic "last in, first
out" stack logic. When the user is done with the current activity and
presses the Back button, that activity is popped from the stack and
destroyed, and the previous activity resumes.
Does this also apply to the "MainActivity"? If the "MainActivity" is destroyed does that cause the App to crash i.e does the lifecycle of the MainActivity in any way differs from the lifecycle of any other activity? Is the MainActivity the last activity that is being stopped when the App is exited?
Why do I need this:
I would like to free some resources when the App is exited (in the onStop() Method (because post Honeycomb it is guaranteed that onStop will be called)), especially ExecutorServices, I've read here that even though App is exited there is no guarantee that an ExecutorService will be stopped and will make JVM continue working/running, even though App is closed/killed and will continue to use system resources.
Main Activity is the entry point for your app when user presses the icon for cold launch. You make any of your Activity a main activity in AndroidManifest.xml file via Intent Filter. Intent Filter tells the system which activity is main.
Although main activity is considered first entry point typically, but keep in mind, Main Activity is not always the first activity to be launched, for example there are various intent filters that can be assigned to your other Activity and that activity can be opened directly following the related action. Please read about the Intent-Filter here.
For example, your app is gallery app, typical first screen would be album list. from where you can view individual photo in PhotoActivity. This PhotoActivity can be opened directly via intent from outside apps to view a certain photo without needing to launch the main activity. (Check out google Photos app)
Regarding ExecutorServices or other services lifecycle, few options here:
implement a ownership machanism, ie the activity that starts the service is responsible for closing the service
You can monitor your app's activity stack and kill the service when your Activity stack is empty.
Leverage Application class lifecycle to monitor things.
Reasonable discussion here https://stackoverflow.com/a/5862048/593709
I have an Activity which can open 2 different Fragments by 2 different Buttons. By the default that Activity when it creates, it is opening a Fragment, we call it "The Main Fragment".
The first Fragment to which we are going over by the first Button we meet zero problems with the Rotation, but the second one after the rotation disappears and the screen shows the Main Fragment's content. When I tried to rotate the screen back, I see the Main Fragment's content again. But why it is so, if I didn't write any code, which must return me to the Main Fragment without clicking a button.
What assumptions do you have?
Why this is happening ?
Default Behavior, Actiivty is getting recreated on orientation change so your fragment are.
Explanation
You need to understand Activity Life Cycle to understand why this is happening.
First, “rotating the screen” is not the actual scenario we are talking about today. Because any configuration change will cause Android to restart your Activity. A configuration change might be the device rotating (because now we have a different screen layout to draw upon), or it could be a language switch (because we need to re-write all those strings, which may need more room now OR it could be the scary RTL switch!), or even keyboard availability.
By reloading your app, what the system is actually doing is calling onDestroy() and then immediately calling onCreate(). This way, your Activity is as fresh as possible, with all of the right creation data (even though the user has been with you the entire time).
Now you have following option -
Either Fix Orientation for your app from AndroidManifest.xml
But oviously that is not a very good experience for user.
Save activityState with onSaveInstanceState()
This method will be called before onDestroy(). And, when your Activity is created, there’s a matching step onRestoreInstanceState(), which will also be called automatically. All of these automatic steps mean that you can let the system worry about saving and loading your data, because you planned ahead and mapped out what was important. (Or, you can skip onRestoreInstanceState() and load your saved state from the Bundle that comes with onCreate().
In you integrate Fragment in activity, because activity is getting destroy() so your fragment will also destroy() and will be recreated.
Please take a good read on Handling Configuration Change and this.
Once you understood the concepts things will start falling into your but it will only happen if you will complete your learning curve.
Happy Coding !
That is because onCreate is being called every time the screen is rotated. Probably you are displaying The Main Fragment from your onCreate method. You will face the same issue if you put your fragment display logic in onResume because just after onCreate, onResume is called.
Solution: store the fragment on top in shared preferences that way you know what to display every time onCreate is being called.
I need a way to restore previous Android task when the current task (my application) is put in background using either back or overview button. For example, a video is played by youtube app when a SIP call is received. The softphone task is brought to foreground, then the call is answered. Once the call finishes, by pressing back or overview button youtube app is shown and the video continues playing. An example of such Android application is Linphone. I would like to know how this can be achieved programmatically.
As stated by others and here, Android handles it automatically for you. But if you need to add anything explicitly when going/coming to/from the background state then you can also override onSaveInstanceState() and onRestoreInstanceState() methods which will be called accordingly.
As your activity begins to stop, the system calls the onSaveInstanceState() method so your activity can save state
information to an instance state bundle. The default implementation of
this method saves transient information about the state of the
activity's view hierarchy, such as the text in an EditText widget or
the scroll position of a ListView widget.
To save additional instance state information for your activity, you must override onSaveInstanceState() and add key-value pairs to the
Bundle object that is saved in the event that your activity is
destroyed unexpectedly. If you override onSaveInstanceState(), you
must call the superclass implementation if you want the default
implementation to save the state of the view hierarchy.
#Override
protected void onRestoreInstanceState(Bundle outState) {
if (outState != null) {
Crashlytics.log(1, "FormActivity", "Method:onRestoreInstanceState, Msg: saved instance is not null");
if (outState.containsKey("record")
&& Session.getCurrentRecord() == null) {
Session.setCurrentRecord(
gson.fromJson(
outState.getString("record"),
Record.class
)
);
}
if (outState.containsKey("user")
&& Session.getCurrentUser() == null) {
Session.setCurrentUser(
gson.fromJson(
outState.getString("user"),
User.class
)
);
}
}
super.onRestoreInstanceState(outState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Session.setCurrentRecord(record);
outState.putString("record", gson.toJson(Session.getCurrentRecord()));
outState.putString("user", gson.toJson(Session.getCurrentUser()));
super.onSaveInstanceState(outState);
}
Source 1 Source 2
This is done automatically by the android system.
Now why you may not be able to notice this behavior for your app.
You may be launching your app from the app launcher. Which means that you already put all other apps (except the launcher) in background. Now depending on the launcher settings you may go on page from where you launched the app or home when you press back button.
When can you observe this behavior
If your activity is launched from background service, e.g. broadcast receiver
If your activity is launched by clicking on a notification button
basically when your activity is created without killing or putting other apps in background, you will get back to the same app when your app is closed.
Exception - If you use home button all apps go to background and home screen appears.
hope this helps.
here is the official documentation on how to preserve the UI state:
https://developer.android.com/topic/libraries/architecture/saving-states
if the user configured the phone to always kill activities in background or they have limited resources then you have to handle that, but in some cases (your activity wasn't killed and remained in memory) as Mayank answered the system will do it for you.
getting a call from phone app will interrupt your app (System-initiated UI state dismissal)
what you should do as suggested by the documentation above:
In the section: Managing UI state: divide and conquer
Local persistence: Stores all data you don’t want to lose if you open and close the activity. Example: A collection of song
objects, which could include audio files and metadata.
ViewModel: Stores in memory all the data needed to display the associated UI Controller. Example: The song objects of the most
recent search and the most recent search query.
onSaveInstanceState(): Stores a small amount of data needed to easily reload activity state if the system stops and then recreates
the UI Controller. Instead of storing complex objects here, persist
the complex objects in local storage and store a unique ID for
these objects in onSaveInstanceState(). Example: Storing the most
recent search query.
so In your case have a view model that stores the Url and the video time when the call got received
and I would also store the same info in the instanceState using the proper life cycle hooks
here is a good SO thread with example on how to use the savedInstanceState :
Saving Android Activity state using Save Instance State
it has old and new answers, you may want to read through it to get a sense of how things changed overtime
basically the three bullet points above are the recommended strategy by official documentation
I have an app that has a few screens.
The Main screen automatically opens a "new" screen if it's the first time the user opens the app.
I then set a boolean variable (on the Main screen) keeping track of this.
The intention is if the user goes back to the Main screen, the code that opens the "new" screen can be skipped.
The problem is that the variable keeps getting reset on OnCreate.
So, I added some code to use SharedPreferences.
This works; however, I want to clear the variable when the app exits.
(I want the "new" screen to open every time the app opens the first time).
So, looking at the lifecycle I tried both onStop and onDestory.
The SharedPreferences are cleared but... not when the app is exited; but when the "new" screen appears.
Am I looking at the lifecycle wrong?
Is there some sort of global variable I can declare that only lives while the app is open?
This functionality is the requirement, so I cannot change it.
You should use onSaveInstanceState and onRestoreInstanceState, they will keep the boolean alive if your activity calls onCreate but not if you exit and come back later.
See this answer for implementation:
Saving Android Activity state using Save Instance State
You can define the variable in the line one of ur whole code, that way it will only reset when the app is opened again.
I have a ListFragment which depends on the hosting Activity to properly initialize. On first run, it loads up fine. Once I change the orientation, my app crashes. From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
I have setRetainInstance(false) set in the onStart method but can't find any method to disable the restoring of the Fragment once the orientation changes. Any ideas? Do I need to remove the Fragment prior to my app being destroyed?
Edit: I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I have a ListFragment which depends on the hosting Activity to properly initialize.
That may be your difficulty right there.
From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
Correct.
Any ideas?
I would focus on handling configuration changes properly. Between onSaveInstanceState() in the fragment and the combination of onRetainNonConfigurationInstance(), getLastNonConfigurationInstance() (both on Activity) and onAttach() (on your Fragment), you should be able to pass whatever stuff is in the old fragment to the new one without crashing. For configuration changes, do not rely upon "the hosting Activity to properly initialize".