Skip to content

Commit

Permalink
Avoid changing back stack when fragment manager is not resumed. (#237)
Browse files Browse the repository at this point in the history
This change fixes the problem when there are changes being made to the stack while the hosting activity is in paused state (e.g. an activity-based dialog from google play services). In such a case it is not allowed to do any changes which can affect fragment manager's state (e.g. updating backstack). For other changes we use `commitAllowingStatLoss` to indicate we are not interested in fragment manager handling their restoration and hence we can perform most operations. Unfortunately installing back handler is not allowed without state change and we need to wait until the fragment host is resumed before we install it.
  • Loading branch information
kmagiera authored Nov 27, 2019
1 parent 0927e03 commit cbc86bb
Showing 1 changed file with 19 additions and 5 deletions.
24 changes: 19 additions & 5 deletions android/src/main/java/com/swmansion/rnscreens/ScreenStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import android.content.Context;
import android.view.View;
import android.view.WindowInsets;

import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

Expand Down Expand Up @@ -34,6 +34,15 @@ public void onBackStackChanged() {
}
};

private final FragmentManager.FragmentLifecycleCallbacks mLifecycleCallbacks = new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentResumed(FragmentManager fm, Fragment f) {
if (mTopScreen == f) {
setupBackHandlerIfNeeded(mTopScreen);
}
}
};

public ScreenStack(Context context) {
super(context);

Expand Down Expand Up @@ -93,22 +102,21 @@ protected ScreenStackFragment adapt(Screen screen) {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
FragmentManager fm = getFragmentManager();
fm.removeOnBackStackChangedListener(mBackStackListener);
getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
if (!fm.isStateSaved()) {
// state save means that the container where fragment manager was installed has been unmounted.
// This could happen as a result of dismissing nested stack. In such a case we don't need to
// reset back stack as it'd result in a crash caused by the fact the fragment manager is no
// longer attached.
fm.removeOnBackStackChangedListener(mBackStackListener);
fm.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mTopScreen != null) {
setupBackHandlerIfNeeded(mTopScreen);
}
getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
}

@Override
Expand Down Expand Up @@ -238,6 +246,12 @@ public void run() {
* that case we want the parent navigator or activity handler to take over.
*/
private void setupBackHandlerIfNeeded(ScreenStackFragment topScreen) {
if (!mTopScreen.isResumed()) {
// if the top fragment is not in a resumed state, adding back stack transaction would throw.
// In such a case we skip installing back handler and use FragmentLifecycleCallbacks to get
// notified when it gets resumed so that we can install the handler.
return;
}
getFragmentManager().removeOnBackStackChangedListener(mBackStackListener);
getFragmentManager().popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
ScreenStackFragment firstScreen = null;
Expand Down

0 comments on commit cbc86bb

Please sign in to comment.