PopBackStack in onPostExecute raises IllegalStateException

Sorry this is a rather long post, let me first try to explain the background:

I read a lot of posts on this topic (and Alex is a great blog post on this topic), and the general conclusion seems to be to not execute fragment transactions in an asynchronous callback (see Dianne post ) like AsyncTask#onPostExecute() .

However, I have 2 cases where this is necessary:

  • Activity showing the Fragment login, when the user presses the login button, AsyncTask starts authentication from the server, then when the login is returned, the login Fragment is replaced with the Fragment Main application.
  • An Activity , showing the main fragment of the application, when the user starts an action that requires logging in, the login fragment replaces the main fragment that is added to the backstack. Again, when the login button is pressed, AsyncTask authenticates with the server, then when the login is successful, we want to pop back to show the main Fragment user and let them perform the action that they wanted to perform.

Case 1 can be resolved using commitAllowingStateLoss , but Case 2 is complicated because there is no such taste for popBackStack in the FragmentManager .

In any case, both of these cases require special handling of the application going into the background during AsyncTask#doInBackground() , calling onPostExecute() when the application is in the background. One solution is to use Fragment.isResumed to protect the replacement of the fragment or pop-stop, and then process the process killed from the situation by logging in again or saving some flag indicating a recent successful login and replacing / appearing the login fragment in the state application recovery (login Fragment restored up to the FragmentManager ). Or, resolve the loss of state and process the process, and then restore the situation, check the recent login and delete the login fragment.

How do you handle this? It seems like a lot of work to deal with a very common situation.

+4
source share
2 answers

Like x90 mentioned in the comment above, the simplest solution would be to split the fragments into separate actions. Obviously, this throws an exception, since starting a new action does not require changing the state of the previous activity. Exchanging fragments to / from the screen, as this is probably not what you want to do anyway ... as their names show, Fragment was intended to be used as "fragments" of the user interface, and not as much as whole screens that make up the user interface. (Of course, I don't want to assume that you are not allowed to use Fragment in this way ... I'm just saying that this is not the purpose of the Fragment API design).

You can also try to implement some kind of cancellation policy in your AsyncTask . That is, if activity ever starts going into the background, cancel the task immediately. When AsyncTask finally finishes, make sure that isCancelled() returns false before performing fragment transactions, etc.

+1
source

A later workaround is to call FragmentActivity.onStateNotSaved() before popBackStack() .

+3
source

Source: https://habr.com/ru/post/1501994/


All Articles