Fragment transactions and activity status lost

Source: Internet
Author: User

This article by Bole online-lone lonely hao days translation. without permission, no reprint!
English Source: Androiddesignpatterns. Welcome to join the translation team.

The following stack traces and exception codes have been confusing StackOverflow since the initial release of Honeycomb.

12345 java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

This blog will explain when and why this anomaly occurred. And there are several ways to make this exception not happen in your application.

Why is this exception thrown?

The occurrence of this anomaly is due to the attempt to commit a fragmenttransaction after the activity state has been saved. This behavior is known as Active state loss (activity states Loss). Before we know the true meaning of this anomaly, however, let's take a look at onSaveInstanceState() what happens when the function is called.

As I recently discussed in the Binders & Death Recipients blog, Android apps are difficult to determine their own destiny in the Android runtime environment. The Android system can release memory at any time by ending a process, and background activities may be cleaned up without warning. To ensure that this indeterminate behavior is transparent to the user, the onSaveInstanceState() schema gives each activity an opportunity to save its own state before the activity can be destroyed by invoking the method. Switching between foreground and background activities provides the user with a seamless transition experience when reloading a saved state. Users don't have to worry about whether the activity is destroyed by the system.

When the framework invokes onSaveInstanceState() a method, it passes a bundle object to the method. Activity can use this object to store its state, and activity keeps its dialogs, fragments, and views state in this object. When this function returns, the system packages the bundle object through a binder interface to the system service processing, which is then securely stored. When the system decides to recreate the activity, it returns the same bundle object to the application, which can reload the state of the activity when it is destroyed.

Then why do you throw this exception? The problem stems from the fact that the bundle object represents an instantaneous snapshot of the activity in the calling onSaveInstanceState() method, and that's all. This means that when you call Fragmenttransaction, the onSaveInstanceState() commit method is called after the method call. This transaction will not be remembered because it is not recorded in the first time as part of the state of the activity. From the user's point of view, this transaction will be lost and may cause the UI state to be lost. To ensure the user's experience, Android avoids the loss of state at all costs. Therefore, whenever it happens, it will simply throw a illegalstateexception exception.

When will this exception be thrown?

If you have encountered this exception before, you may have noticed that the time of the exception throw differs slightly from platform to version. You may find that older machines are less prone to throwing exceptions, or that your app uses the support library to throw exceptions more often than the official framework class. This subtle distinction has led some people to speculate that the support library has bugs and is not worth believing. However, such conjecture is completely wrong.

These nuances exist because of the great changes that have been made to the activity life cycle of honeycomb. Before honeycomb, the activity is not considered destroyed until it is paused. This means that the onPause() onSaveInstanceState() method is called immediately before the method. However, starting with Honeycomb, considering destroying the activity only after they have stopped, this means that the onSaveInstanceState() method is now onStop() called before the method, instead of being onPause() called before the method. These differences are summarized in the following table:

Previous versions of Honeycomb Honeycomb and newer versions
Activities will be terminated before the OnPause () call? NO NO
Activities will be terminated before the OnStop () call? YES NO
What method calls will be executed before the onsaveinstancestate (Bundle)? OnPause () OnStop ()

As a result of the subtle changes that have been made to the activity life cycle, the support library sometimes needs to change its behavior based on the version of the platform. For example, in honeycomb and above, whenever a commit method is onSaveInstanceState() called after a method, an exception is thrown to alert the developer that a state loss has occurred. However, on devices prior to honeycomb, each time it occurs and throws an exception is more restrictive, their onSaveInstanceState() methods are called earlier in the activity's life cycle, and the results are more prone to state loss. The Android team was forced to make a compromise: in order to better interact with the older version of the platform, the old device had to accept that accidental state loss could occur onPause() between methods and approaches onStop() . The behavior of the support library on different platforms is summarized in the following table:

Previous versions of Honeycomb Honeycomb and newer versions
Commit () is called before OnPause () Ok Ok
Commit () is called in between OnPause () and OnStop () execution State LOSS Ok
Commit () is called after OnStop () EXCEPTION EXCEPTION
How do I avoid throwing exceptions?

Once you understand what's going on, it's easy to avoid the loss of activity status. If you read this blog, you are lucky to have a better understanding of how the support library works and why it is so important to avoid state loss in your application. If you're looking at this blog to find a quick fix, keep these tips in mind when you use Fragmenttransactions in your app:

Suggested a

Be careful when you submit transactions in the activity life cycle function. Most applications simply onCreate() commit transactions at the start of the method invocation, or when the corresponding user enters it, it is impossible to run into any problems. However, when your transactions is submitted in other activity life cycle functions, such as onActivityResult() , onStart() and onResume() , things will become subtle. For example, you should not submit transactions in the Fragmentactivity onResume() method. Because sometimes this function can be called before the state of the activity is restored (you can see the relevant document for more information). If your application requires onCreate() that transaction be submitted in an activity life cycle function other than a function, you can submit it in fragmentactivity onResumeFragments() function or activity onPostResume() function. These two functions ensure that the activity reverts to its original state before it is called, thus avoiding the possibility of state loss. (Example: Take a look at my answer to this stackoverflow question to think about how to commit fragmenttransactions as the Onactivityresult method of the activity is called response).

Recommendation two

Avoid committing transactions in asynchronous callback functions. This includes commonly used methods, such as the OnPostExecute method of Asynctask and the Onloadfinished method of Loadermanager.loadercallbacks. The problem with executing transactions in these methods is that when they are called, they do not have the current state of the activity life cycle at all. For example, consider the following sequence of events:

    1. An activity executes a asynctask.
    2. The user presses the "Home" key, causing the activity onSaveInstanceState() and onStop() method to be called.
    3. Asynctask completes and the OnPostExecute method is called, and it is unaware that the activity is over.
    4. The fragmenttransaction that is committed in the OnPostExecute function causes an exception to be thrown.

In general, the best way to avoid this type of exception is to not commit transactions in an asynchronous callback function. Google engineers seem to agree with this creed. According to this article on Android Developers Group, the Android team believes that the main change in the UI stems from the bad user experience of submitting fragmenttransactions from an asynchronous callback function. If your application needs to execute transaction in these callback functions, there is no easy way to ensure that the callback function is not good to be onSaveInstanceState() called later. You may need to resort to using the Commitallowingstateloss method and handle the loss of state that can occur. (You can take a look at two other articles on StackOverflow, this one and another article).

Recommendation three

As a final approach, use the commitAllowingStateLoss() function. commit() commitAllowingStateLoss() The only difference between a function and a function is that when a state is lost, the latter does not throw an exception. Usually you should not use this function because it means that state loss may occur. Of course, a better solution is to make sure that the commit function is called before the state of the activity is saved, so that there is a good user experience. You should not use a function unless the state is lost and may be unavoidable commitAllowingStateLoss() .

Fragment transactions and activity status lost

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.