Zhuinden / simple-stack

[ACTIVE] Simple Stack, a backstack library / navigation framework for simpler navigation and state management (for fragments, views, or whatevers).
Apache License 2.0
1.36k stars 76 forks source link

How to not retain fragment when navigating #262

Closed omkar-tenkale closed 2 years ago

omkar-tenkale commented 2 years ago

I have 2 fragments A and B

AKey() -> A() -> BKey() -> B() -> goBack()

Expected behaviour: AKey's createFragment should be called again and new fragment object instance to be created

Actual behaviour: Old A instance's onCreateView is called again

Problem: Some variables initialised in A keep their value but fragment is designed in a way which expects default values for fields in onCreateView

Is this an issue with how i'm initialising fragments or should i work with manual statechanger or what.. i'm confused

Zhuinden commented 2 years ago

A's view is destroyed, because DefaultFragmentStateChanger uses attach/detach by default. From library perspective, this makes most sense, as Google explicitly refused to make it so that the lifecycle of a fragment becomes inactive when it is hidden + it is impossible to make an AndroidX Fragment be both stopped and have a view at the same time.

So if I had used show/hide by default instead of attach/detach, people would be complaining about how their LiveData observers don't get cancelled when they navigate forward and their fragment is off-screen. This would also be because of Google's code, and there would be no way around it other than destroying the view (or creating a 3rd fragment view lifecycle that takes hidden into account, but it's not a very common thing to do).

Some variables initialised in A keep their value but fragment is designed in a way which expects default values for fields in onCreateView

Well you are supposed to extract the state either into the Fragment or into a scoped model like so and save-restore it across process death like so because of how Android works.


However, it is possible to retain the view of fragments quite easily actually, because simple-stack is configurable like that (unlike Jetpack Navigation where you'd basically need to rewrite their entire Fragment integration lol)

So keeping views is as simple as this (but it will make your Fragment not be stopped when you go to another screen, it calls onHiddenChanged instead)

public class KeepViewFragmentStateChanger extends DefaultFragmentStateChanger {
    public KeepViewFragmentStateChanger(FragmentManager fragmentManager, int containerId) {
        super(fragmentManager, containerId);
    }

    @Override
    protected void startShowing(@Nonnull FragmentTransaction fragmentTransaction, @Nonnull Fragment fragment) {
        fragmentTransaction.show(fragment);
    }

    @Override
    protected void stopShowing(@Nonnull FragmentTransaction fragmentTransaction, @Nonnull Fragment fragment) {
        fragmentTransaction.hide(fragment);
    }

    @Override
    protected boolean isNotShowing(@Nonnull Fragment fragment) {
        return fragment.isHidden();
    }
}
Zhuinden commented 2 years ago

If you need to completely kill A when you go to B (and not be able to navigate back to it on back), then use replaceTop, setHistory or exitScopeTo

omkar-tenkale commented 2 years ago

If you need to completely kill A when you go to B (and not be able to navigate back to it on back),

I want to completely kill A AND be able to navigate back!

Zhuinden commented 2 years ago

@omkar-tenkale then use setHistory with a different fragment tag (see that uuid option in the other issue 😜 ) when you are navigating to A

omkar-tenkale commented 2 years ago

isn't there a better solution? 😅

Zhuinden commented 2 years ago

Well, you're trying to destroy the previous fragment, so you need to have a different key for it - or at least a key that provides a different fragment tag.

So setHistory sounds like the way to go 🤔

omkar-tenkale commented 2 years ago

Closing for now ..