0

I have 10 activities. Also I has 20 fragments.

Every of them work with UI. If work with UI (e.g. after minimize application) after called method onSaveInstanceState() then throw exception: Can not perform this action after onSaveInstanceState

To fix this I check on EVERY fragments and activities is application is visibility (I write custom mehtod for this). And if result is true ONLY then start work with UI.

Ok it's fix the problem. But I think this is a NOT the best solution.

Any another solution to fix this problem?

P.S. The root framgent and root activity is not good solution because the logic will be duplicate.

Alexei
  • 14,350
  • 37
  • 121
  • 240
  • In what condition do you get `Can not perform this action after onSaveInstanceState`? – azizbekian Mar 18 '17 at 14:29
  • when I try to do this: fragmentTransaction.beginTransaction().replace(R.id.my_frag_cont, fragment).commit(); – Alexei Mar 18 '17 at 15:11
  • See the answers for this question. They give an explanation to the issue and possible solutions. http://stackoverflow.com/questions/7469082/getting-exception-illegalstateexception-can-not-perform-this-action-after-onsa – Juan Mar 18 '17 at 15:37

1 Answers1

1

This problem is normally a symptom of a deeper problem with the architecture of your app. You tend to see it when there is not proper separation of concerns between the view layer and business logic layer.

I imagine you are doing some async work directly in the Activity/Fragment and then trying to do a Fragment Transaction when the result comes back.

There are a number of things you can do to solve this problem:

Don't use Fragments

There is almost never a need to use a Fragment - 90% of the time you could achieve the same result using a ViewGroup and avoid all the lifecycle headaches, random crashes & otherwise erratic behaviour Fragments cause.

The only times I'd use a Fragment were if I needed a specific lifecycle callback (onActivityResult) or if I'm forced to by a third party library (Android Pay, Braintree).

Separate Your View via an Interface

This is basically what the MVP/MVVM patterns are all about. It is separating your View from your business Logic (Presenter/ViewModel). This would help you because your Activity/Fragment would implement the View interface:

public class MyActivity implements MyView { ...

When your activity starts it binds to the Presenter and when it finishes it unbinds:

protected void onCreate(Bundle bundle) {
    // ...
    presenter.bind(this);
}

protected void onDestroy() {
    // ...
    presenter.unbind(this);
}

Now when in your business logic an async operation finishes and tries to update the view, if the Activity has finished the View will have been unbound. You can either null check it or (as I prefer) have a no-op View in its place.

Don't Update Your View From Long Running Async Operations

Where possible don't update your view directly from the results of a long running async process (network or heavy computation). Instead cache the results in the persistence layer (db/prefs/file). Have your view then subscribe to data from the persistence layer.

The subscription could be done in several ways - RxJava, event bus notification, static callback.

This way when the result comes back it just gets saved. If the view is still active it gets notified and loads the results from persistence. If not it can pick them up from there the next time it is loaded.

Finally

As an aside you can call .commitAllowingStateLoss() instead of just .commit() and it won't crash. This doesn't really fix the underlying problem though...

Jahnold
  • 7,623
  • 2
  • 37
  • 31