mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-27 01:34:25 +08:00
[android] Fix re-attaching ScreenContainer to window (#272)
Code to reproduce and test: https://snack.expo.io/@angelikaserwa/humiliated-bagel. Switch to the Settings tab, then go back to the Home tab and press the details button. Nothing happens. It was because after re-attaching we were using a destroyed FragmentManager that was cached inside the ScreenContainer class. Then, when we go back from Details to Home screen, using a hardware back button, an exception occured: `The specified child already has a parent. You must call removeView() on the child's parent first`. I fixed this by calling `removeAllViews()` when detaching container from window and forcing an update on re-attach.
This commit is contained in:
committed by
Krzysztof Magiera
parent
518c094657
commit
3fc74e29ab
@@ -25,7 +25,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
private final Set<ScreenFragment> mActiveScreenFragments = new HashSet<>();
|
||||
private final ArrayList<Runnable> mAfterTransitionRunnables = new ArrayList<>(1);
|
||||
|
||||
private @Nullable FragmentManager mFragmentManager;
|
||||
protected @Nullable FragmentManager mFragmentManager;
|
||||
private @Nullable FragmentTransaction mCurrentTransaction;
|
||||
private @Nullable FragmentTransaction mProcessingTransaction;
|
||||
private boolean mNeedUpdate;
|
||||
@@ -184,16 +184,9 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
return ((FragmentActivity) context).getSupportFragmentManager();
|
||||
}
|
||||
|
||||
protected final FragmentManager getFragmentManager() {
|
||||
if (mFragmentManager == null) {
|
||||
mFragmentManager = findFragmentManager();
|
||||
}
|
||||
return mFragmentManager;
|
||||
}
|
||||
|
||||
protected FragmentTransaction getOrCreateTransaction() {
|
||||
if (mCurrentTransaction == null) {
|
||||
mCurrentTransaction = getFragmentManager().beginTransaction();
|
||||
mCurrentTransaction = mFragmentManager.beginTransaction();
|
||||
mCurrentTransaction.setReorderingAllowed(true);
|
||||
}
|
||||
return mCurrentTransaction;
|
||||
@@ -247,6 +240,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mIsAttached = true;
|
||||
mFragmentManager = findFragmentManager();
|
||||
updateIfNeeded();
|
||||
}
|
||||
|
||||
@@ -254,6 +248,13 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mIsAttached = false;
|
||||
|
||||
// fragment manager is destroyed so we can't do anything with it anymore
|
||||
mFragmentManager = null;
|
||||
// so we don't add the same screen twice after re-attach
|
||||
removeAllViews();
|
||||
// after re-attach we'll update the screen and add views again
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
private final FragmentManager.OnBackStackChangedListener mBackStackListener = new FragmentManager.OnBackStackChangedListener() {
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
if (getFragmentManager().getBackStackEntryCount() == 0) {
|
||||
if (mFragmentManager.getBackStackEntryCount() == 0) {
|
||||
// when back stack entry count hits 0 it means the user's navigated back using hw back
|
||||
// button. As the "fake" transaction we installed on the back stack does nothing we need
|
||||
// to handle back navigation on our own.
|
||||
@@ -70,24 +70,22 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
FragmentManager fm = getFragmentManager();
|
||||
fm.removeOnBackStackChangedListener(mBackStackListener);
|
||||
getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
|
||||
if (!fm.isStateSaved()) {
|
||||
mFragmentManager.removeOnBackStackChangedListener(mBackStackListener);
|
||||
mFragmentManager.unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks);
|
||||
if (!mFragmentManager.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.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
mFragmentManager.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
}
|
||||
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
|
||||
mFragmentManager.registerFragmentLifecycleCallbacks(mLifecycleCallbacks, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,8 +228,8 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
// 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);
|
||||
mFragmentManager.removeOnBackStackChangedListener(mBackStackListener);
|
||||
mFragmentManager.popBackStack(BACK_STACK_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
ScreenStackFragment firstScreen = null;
|
||||
for (int i = 0, size = mStack.size(); i < size; i++) {
|
||||
ScreenStackFragment screen = mStack.get(i);
|
||||
@@ -241,14 +239,14 @@ public class ScreenStack extends ScreenContainer<ScreenStackFragment> {
|
||||
}
|
||||
}
|
||||
if (topScreen != firstScreen && topScreen.isDismissable()) {
|
||||
getFragmentManager()
|
||||
mFragmentManager
|
||||
.beginTransaction()
|
||||
.hide(topScreen)
|
||||
.show(topScreen)
|
||||
.addToBackStack(BACK_STACK_TAG)
|
||||
.setPrimaryNavigationFragment(topScreen)
|
||||
.commitAllowingStateLoss();
|
||||
getFragmentManager().addOnBackStackChangedListener(mBackStackListener);
|
||||
mFragmentManager.addOnBackStackChangedListener(mBackStackListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user