Is the method onSaveInstanceState(Bundle) called after onPause()? - java

I'm new to android and I read a book for beginners which said that onSaveInstanceState(Bundle) is ensured to be called before the system reclaims your Activity.
I tried it on some test codes and found it incorrect. I found that onSaveInstanceState(Bundle) was called every time after onPause() was called. And it has nothing to do with system reclaimation.
I'm not very sure about it, so that's the question: when is onSaveInstanceState(Bundle) called actually?

I don't agree with a previous answer.
According to the Documentation:
If called, this method will occur before onStop(). There are no
guarantees about whether it will occur before or after onPause().

According to Android Documentation:
In addition, the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state, allowing you to save away any dynamic instance state in your activity into the given Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created. See the Process Lifecycle section for more information on how the lifecycle of a process is tied to the activities it is hosting. 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.
Yes onPause() is called before onSaveInstanceState(Bundle). But onPause() is guaranteed to be called as its a part of activity life cycle
Usually when your activity is re-created for example when you change device orientation then onSaveInstanceState(Bundle) is called if you have not specified the android:configChanges tag in your manifest.xml file.

Related

What is the Difference between onResume() and onPostResume() in Activity Life Cycle?

While Learning Activity LifeCycle in Android, I am confused about these two methods. I tried to implement both of them separately and are working fine. So, What's the difference between these two twins?
onResume():
protected void onResume()
Called after onRestoreInstanceState(Bundle), onRestart(), or onPause(), for your activity to start interacting with the user. This is an indicator that the activity became active and ready to receive input. It is on top of an activity stack and visible to user.
On platform versions prior to Build.VERSION_CODES.Q this is also a good place to try to open exclusive-access devices or to get access to singleton resources. Starting with Build.VERSION_CODES.Q there can be multiple resumed activities in the system simultaneously, so onTopResumedActivityChanged(boolean) should be used for that purpose instead.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
If you override this method you must call through to the superclass implementation.
 onPostResume():
protected void onPostResume()
Called when activity resume is complete (after onResume() has been called). Applications will generally not implement this method; it is intended for system classes to do final setup after application resume code has run.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
If you override this method you must call through to the superclass implementation.
onPostResume :
Called when activity resume is complete (after activity's {#link #onResume} has been called). Applications will generally not implement this method; it is intended for system classes to do final setup after application resume code has run.
It will do following things
It will ensure that screen is visible to user and will do the final set up for activity.
Remove any pending posts of messages with code 'what' that are in the message queue.
Check all fragment gets resumed and Moves all Fragments managed by the controller's FragmentManager into the resume state.
Execute any pending actions for the Fragments managed by the controller's FragmentManager.
If you check it life cycle vise it worked like below
onResume() - Activity
onResume() - Fragment check third point as explained above
onPostResume() - Activity
See here please: Activity life cycle methods : onPostResume significance

How to find out from an activity that another activity got terminated

I have 2 activities
Activity A has a registered receiver that updates a static generic list.
Activity B accesses the static generic list in Activity A.
The problem is:
If Activity A ended (killed by the system), the registered receiver stops, which makes the data in the static generic list unreliable, as it depends on the registered receiver to be updated.
And the biggest problem that the static generic list doesn't get terminated (null / zeroed) along with the registered receiver, though both of them created by the same activity.
So there's no way for me to know that my static generic list has become unreliable to reload it all over with fresh data when Activity B gets created.
Also there's no way - listener - to listen to the registered receiver termination, where I'd have terminated the generic static list, and check it in Activity B creation, if it's null, I'll reload a fresh data.
And as you know it's not guaranteed that onDestroy will get called when the system terminates the activity, otherwise I'd have terminated the generic static list.
I even added a static Boolean var (mAlive) to Activity A that has a default value (false) and becomes (true) in onCreate, in hope that when Activity A gets destroyed, (mAlive) will become false (the default value in its declaration), which I could check in Activity B to know that the registered receiver is terminated and the data is unreliable and reload it again, but it turns out, that even destroying Activity A, doesn't reset static Boolean var (mAlive) to its default value (false).
So, any suggestions please, I got a brain freeze trying to find a solution in the past 2 weeks.
Thank you
You seem to be greatly misunderstanding the Activity Lifecycle.
Only one Activity at a time can be running. The current one is suspended when a new one starts and you cannot access directly anything contained in one Activity from a different Activity. Static variables can hold simple data but that is not recommended as a way to avoid dealing with the Activity Lifecycle.
To pass data between activities, you use Intents and Extras.
How do I pass data between Activities in Android application?
If you want two Activities to share the same data, you could use a Service that contains the data which can be accessed from both Activities.
You can fire a Broadcast(BroadcastReceiver Example) from your desired activity's onDestroy() method. Afterwards Receive broadcast in your required activity.
You can put your data into a separate object so you don't dipend on your activity A's lifecycle. You can see an example here at Finder section
I think you could make a parent activity extended by both your Activity A and B. In your parent activity you could register your receiver into its onResume method and then unregister it into its onPause method. By this way you should have always your receiver registered to the current activity.
Then if you have read the previous link, if you make a Finder responsible to keep your fresh data and you reference it into your parent Activity (so you have a reference into both Activity A and Acitivity B) you should be sufficiently sure that a variable referenced by the current active activity can't be destroyed by the system.
I'm not sure to have understood what you need, let me know

Android show dialog causes illegal state exception if activity recreated

There are three activities: Login, Main and Profile
Obviously from Login you can go to Main. There is a Button that calls AppCompatDialogFragment in Main.
BalanceCalculationDialog dialog = BalanceCalculationDialog.newInstance(model);
dialog.setListener(this);
dialog.show(getSupportFragmentManager(), "TAG");
If I user enters Main for the first time dialog shows.
If user goes to Profile and then backs dialog shows.
If user goes out from Main (finish() with Intent#FLAG_ACTIVITY_NEW_TASK and Intent#FLAG_ACTIVITY_CLEAR_TASK flags) and tries to see dialog he sees an error.
java.lang.IllegalStateException: Can not perform this action after
onSaveInstanceState....CheckStateLoss()...
As far as I know it caused because "Transaction cannot be commited after onSaveInstanceState()".
I tried to override this method leaving empty body, not calling super and didn't work.
Then I found another way to solve problem, which worked:
#Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
} catch (IllegalStateException e) {
Log.e("ILLEGAL", "Exception", e);
}
}
Nevertheless I don't understand why it works this way -> Number of catching IllegalStateException equals the number of recreating Main. For example I log out 20 times - then I will have 20 catching of mentioned exception. So I don't find this solution as the right one.
In addition, I have other activities that can call another dialogs. These activities also can be finished with finish() and when user opens one of them again he doesn't have the issue.
I would be very glad to have proper explanation of such behaviour and right way of solving it. Thank you very much.
EDIT
Reason of this issue was usage of RxJava EventBus. When I switched to Otto Eventbus problem disappeared. RxJava allows you to send and get messages without subscribe and unsubscribe that can cause unexpected behaviour.
The exception was thrown because you attempted to commit a FragmentTransaction after the activity’s state had been saved, resulting in a phenomenon known as Activity state loss. Before we get into the details of what this actually means, however, let’s first take a look at what happens under-the-hood when onSaveInstanceState() is called. Android applications have very little control over their destiny within the Android runtime environment. The Android system has the power to terminate processes at any time to free up memory, and background activities may be killed with little to no warning as a result. To ensure that this sometimes erratic behavior remains hidden from the user, the framework gives each Activity a chance to save its state by calling its onSaveInstanceState() method before making the Activity vulnerable to destruction. When the saved state is later restored, the user will be given the perception that they are seamlessly switching between foreground and background activities, regardless of whether or not the Activity had been killed by the system.
When the framework calls onSaveInstanceState(), it passes the method a Bundle object for the Activity to use to save its state, and the Activity records in it the state of its dialogs, fragments, and views. When the method returns, the system parcels the Bundle object across a Binder interface to the System Server process, where it is safely stored away. When the system later decides to recreate the Activity, it sends this same Bundle object back to the application, for it to use to restore the Activity’s old state.
So why then is the exception thrown? Well, the problem stems from the fact that these Bundle objects represent a snapshot of an Activity at the moment onSaveInstanceState() was called, and nothing more. That means when you call FragmentTransaction#commit() after onSaveInstanceState() is called, the transaction won’t be remembered because it was never recorded as part of the Activity’s state in the first place. From the user’s point of view, the transaction will appear to be lost, resulting in accidental UI state loss. In order to protect the user experience, Android avoids state loss at all costs, and simply throws an IllegalStateException whenever it occurs.
Solution for this exception is
Be careful when committing transactions inside Activity lifecycle methods. A large majority of applications will only ever commit transactions the very first time onCreate() is called and/or in response to user input, and will never face any problems as a result. However, as your transactions begin to venture out into the other Activity lifecycle methods, such as onActivityResult(), onStart(), and onResume(), things can get a little tricky. For example, you should not commit transactions inside the FragmentActivity#onResume() method, as there are some cases in which the method can be called before the activity’s state has been restored (see the documentation for more information). If your application requires committing a transaction in an Activity lifecycle method other than onCreate(), do it in either FragmentActivity#onResumeFragments() or Activity#onPostResume(). These two methods are guaranteed to be called after the Activity has been restored to its original state, and therefore avoid the possibility of state loss all together. (As an example of how this can be done, check out my answer to this StackOverflow question for some ideas on how to commit FragmentTransactions in response to calls made to the Activity#onActivityResult() method).
Avoid performing transactions inside asynchronous callback methods. This includes commonly used methods such as AsyncTask#onPostExecute() and LoaderManager.LoaderCallbacks#onLoadFinished(). The problem with performing transactions in these methods is that they have no knowledge of the current state of the Activity lifecycle when they are called. For example, consider the following sequence of events:
An activity executes an AsyncTask.
The user presses the “Home” key, causing the activity’s
onSaveInstanceState() and onStop() methods to be called.
The AsyncTask completes and onPostExecute() is called, unaware that the
Activity has since been stopped. A FragmentTransaction is committed
inside the onPostExecute() method, causing an exception to be thrown.
In general, the best way to avoid the exception in these cases is to
simply avoid committing transactions in asynchronous callback methods
all together.
Use commitAllowingStateLoss() only as a last resort. The only difference between calling commit() and commitAllowingStateLoss() is that the latter will not throw an exception if state loss occurs. Usually you don’t want to use this method because it implies that there is a possibility that state loss could happen. The better solution, of course, is to write your application so that commit() is guaranteed to be called before the activity’s state has been saved, as this will result in a better user experience. Unless the possibility of state loss can’t be avoided, commitAllowingStateLoss() should not be used.
But I have to agree that this is an Android framework design defect. Google devs try to fix it over many version. But seems like there is no good approach to work-around this. Just understand the life cycle and remember to check the state of activity carefully before committing transaction

Android: overriding onPause and onResume - proper way

When overriding the onPause() and the onResume() methods of the activity, where is the proper location to call the super.onPause() and super.onResume()? At the beginning of the method or at the end?
From http://developer.android.com/guide/components/activities.html#ImplementingLifecycleCallbacks:
Your implementation of these lifecycle methods must always call the superclass implementation before doing any work, as shown in the examples above.
So, for lifecycle callbacks, like onPause() and onResume(), we should do super.onPause() or super.onResume() at the very beginning. For other methods, it all depends on the semantics of the super class.
Update: This is the accepted answer and it contains a nice amount of good information, including a useful diagram, pulled together into one place. However, it appears to be incorrect, at least according to the current Android documentation which, as the poster points out, is the ultimate source for information on the SDK. Possibly the documentation was clarified after this answer was posted. But, in any case, don't stop reading with this answer, check out espinchi's answer below. It has the documentation on its side.
Placement of the super methods depends only on your preference. It would only matter if those methods were taking parameters OR if you were doing some concurrent work. For example if you do this:
#Override
protected void onPause() {
try {
someOtherThread.join();
} catch (InterruptedException e) {
LOG.e(e);
}
super.onPause();
}
it might block the thread and prevent super from being called.
I suggest that you should read all documentation available because they will help you much. For example this is what you can find in the onPause javadoc. I bolded out the important parts:
Called as part of the activity lifecycle when an activity is going
into the background, but has not (yet) been killed. The counterpart to
onResume().
When activity B is launched in front of activity A, this callback will
be invoked on A. B will not be created until A's onPause() returns, so
be sure to not do anything lengthy here.
This callback is mostly used for saving any persistent state the
activity is editing, to present a "edit in place" model to the user
and making sure nothing is lost if there are not enough resources to
start the new activity without first killing this one. This is also a
good place to do things like stop animations and other things that
consume a noticeable amount of CPU in order to make the switch to the
next activity as fast as possible, or to close resources that are
exclusive access such as the camera.
In situations where the system needs more memory it may kill paused
processes to reclaim resources. Because of this, you should be sure
that all of your state is saved by the time you return from this
function. In general onSaveInstanceState(Bundle) is used to save
per-instance state in the activity and this method is used to store
global persistent data (in content providers, files, etc.)
After receiving this call you will usually receive a following call to
onStop() (after the next activity has been resumed and displayed),
however in some cases there will be a direct call back to onResume()
without going through the stopped state.
Derived classes must call through to the super class's implementation
of this method. If they do not, an exception will be thrown.
I do recommend this flowchart for you it will help your development tremendously:
It probably doesn't matter, but to know for sure, you need to know what the super methods are doing, and usually that information is not available to you.
My style is to call e.g. super.onCreate(), super.onResume(), etc. before the body of my own method, and e.g. super.onPause() and super.onDestroy() after the body of my own method.
The theory behind this is that I like to let the super methods run first while building something up, just in case what I'm doing depends on what the superclass sets up first, and when tearing something down, I like to tear down my own stuff before the superclass tears down its stuff.
There's no right or wrong.
That depends on what you do on your implementation of these methods.
Sometimes you'll want the super to be before your code, and sometime after.
You can put it anywhere. First you have to understand the Activity life cycle. Check the following link Here
Download the demo and run it you will be clear
Delving into the android code, you can find that the framework sets a flag called mcalled when you call super.onPause(). This flag is later checked on resume by the framework.
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onResume()");
}
All you need to do is make sure the call is made to super and you are good. No other precaution is necessary.

Android "single top" launch mode and onNewIntent method

I read in the Android documentation that by setting my Activity's launchMode property to singleTop OR by adding the FLAG_ACTIVITY_SINGLE_TOP flag to my Intent, that calling startActivity(intent) would reuse a single Activity instance and give me the Intent in the onNewIntent callback. I did both of these things, and onNewIntent never fires and onCreate fires every time. The docs also say that this.getIntent() returns the intent that was first passed to the Activity when it was first created. In onCreate I'm calling getIntent and I'm getting a new one every time (I'm creating the intent object in another activity and adding an extra to it...this extra should be the same every time if it was returning me the same intent object). All this leads me to believe that my activity is not acting like a "single top", and I don't understand why.
To add some background in case I'm simply missing a required step, here's my Activity declaration in the manifest and the code I'm using to launch the activity. The Activity itself doesn't do anything worth mentioning in regards to this:
in AndroidManifest.xml:
<activity
android:name=".ArtistActivity"
android:label="Artist"
android:launchMode="singleTop">
</activity>
in my calling Activity:
Intent i = new Intent();
i.putExtra(EXTRA_KEY_ARTIST, id);
i.setClass(this, ArtistActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
Did you check if onDestroy() was called as well? That's probably why onCreate() gets invoked every time instead of onNewIntent(), which would only be called if the activity is already existing.
For example if you leave your activity via the BACK-button it gets destroyed by default. But if you go up higher on the activity stack into other activities and from there call your ArtistActivity.class again it will skip onCreate() and go directly to onNewIntent(), because the activity has already been created and since you defined it as singleTop Android won't create a new instance of it, but take the one that is already lying around.
What I do to see what's going on I implement dummy functions for all the different states of each activity so I always now what's going on:
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy()");
super.onDestroy();
}
Same for onRestart(), onStart(), onResume(), onPause(), onDestroy()
If the above (BACK-button) wasn't your problem, implementing these dummies will at least help you debugging it a bit better.
The accepted answer is not quite correct. If onDestroy() was called previously, then yes, onCreate() would always be called. However, this statement is wrong:
"If you go up higher on the activity stack into other activities and from there call your ArtistActivity.class again it will skip onCreate() and go directly to onNewIntent()"
The "singleTop" section of http://developer.android.com/guide/components/tasks-and-back-stack.html explains plainly how it works (attention to bold text below; I've also proven this through my own debugging):
"For example, suppose a task's back stack consists of root activity A with activities B, C, and D on top (the stack is A-B-C-D; D is on top). An intent arrives for an activity of type D. If D has the default "standard"launch mode, a new instance of the class is launched and the stack becomes A-B-C-D-D. However, if D's launch mode is "singleTop", the existing instance of D receives the intent through onNewIntent(), because it's at the top of the stack—the stack remains A-B-C-D. However, if an intent arrives for an activity of type B, then a new instance of B is added to the stack, even if its launch mode is "singleTop"."
In other words, starting an activity through SINGLE_TOP will only reuse the existing activity if it is already at the top of the stack. It won't work if another activity in that same task is at the top (for example, the activity that is executing startActivity(SINGLE_TOP)); a new instance will be created instead.
Here are two ways to fix this so that you get the SINGLE_TOP behavior that you want -- the general purpose of which is to reuse an existing activity, instead of creating a new one...
First way (as described in the comment section of the accepted
answer): You could add a launchMode of "singleTask" to your Activity. This would force onNewIntent() because singleTask means there can only be ONE instance of a particular activity in a given task. This is a somewhat hacky solution though because if your app needs multiple instances of that activity in a particular situation (like I do for my project), you're screwed.
Second way (better):
Instead of FLAG_ACTIVITY_SINGLE_TOP, use FLAG_ACTIVITY_REORDER_TO_FRONT. This will reuse the existing activity instance by moving it to the top of the stack (onNewIntent() will be called as expected).
The main purpose of FLAG_ACTIVITY_SINGLE_TOP is to prevent the creation of multiple instances of an Activity. For instance, when that activity can be launched via an intent that comes from outside of your application's main task. For internal switching between activities in my app, I've found that FLAG_ACTIVITY_REORDER_TO_FRONT is generally what I want instead.
Set this flag to your intent:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)

Categories

Resources