Closed uvaysss closed 3 years ago
Heyo, well that's a tricky one to answer because there is no way for me to tell if a key "should be different" if it is the same. So currently the only way to "destroy" something is to replace the key with a different key.
Are you sure changes cannot be propagated via for example using a MutableLiveData/BehaviorRelay/etc in a scoped service then using switchMap/switchMap to update the property inside it?
Well, the screen I'm returning back to is a multistack screen, the one from your latest sample. I was trying to avoid such changes, but looks like their is no other way to do it.
I've decided to add backstack.jumpToRoot()
in FragmentStackHostFragment
so that by going this way back, all stacks will have only the initial key in the stack. But it didn't work the way I wanted, I guess it's because the StateChanger is attach only on 1 stack at a time. So Added attach and detach logic for the stacks that aren't currently active.
if (stackHost.isActiveForBack) {
stackHost.backstack.jumpToRoot()
} else {
stackHost.backstack.reattachStateChanger()
stackHost.backstack.jumpToRoot()
stackHost.backstack.detachStateChanger()
}
But I'va faced some other issues. It's not really in scope of this issue, but maybe you could give me a hint.
On this multistack screen I need to change the tab and go to a specific screen by an action. I implemented it also through FragmentStackHostFragment
calling there setHistory()
, but I'm getting some weird behavior. After the setHistory()
when I navigate back in this localStack from that specific screen, the initial screen of this local stack disappears.
What I mean by disappears. In the StateChanger for start and stop I'm using show and hide and when this initial screen of the localStack disappears it is not visible, but the ui is clickable. And also should mention that this initial screen key is always the same, it never changes, it has no arguments (except placeholder).
There is technically one way to destroy/recreate the history, which is to, well, set a new history that does not contain the keys. For example, using backstack.setHistory(History.of(SomeResultScreen()), StateChange.REPLACE)
and then backstack.setHistory(History.of(MainScreen()), StateChange.REPLACE)
would work.
However, instead of that, I personally have been using https://github.com/Zhuinden/live-event (or https://github.com/Zhuinden/event-emitter) to communicate one-off events to the previous screen, which is how I changed the tab on the main screen to whatever I wanted (when the screen came back in front).
but I'm getting some weird behavior. After the setHistory() when I navigate back in this localStack from that specific screen, the initial screen of this local stack disappears.
What I mean by disappears. In the StateChanger for start and stop I'm using show and hide and when this initial screen of the localStack disappears it is not visible, but the ui is clickable. And also should mention that this initial screen key is always the same, it never changes, it has no arguments (except placeholder).
At first glance, the only time I've seen fragments "disappear" like this is when the FragmentManager used for child fragments was NOT actually the childFragmentManager even though it should have been.
Has any of the above input helped?
Sorry for the delay, I was trying to figure out what I might doing wrong.
About the case with "disappearing". I'm using the library for this navigation also, so there cannot be some issue with the wrong fragment manager. But it looks like it happens when I use show/hide, because I didn't catch this behavior with attach/detach. But that's not an option for me. Also, I did look into the multistack sample again and realised that you are using there for the key a simple class , not data class. And if I do not ovveride the hashCode()
it works with no problem with show/hide.
Is there a reason why you didn't use there data class?
You use show/hide like this right?
Is there a reason why you didn't use there data class?
I used non-data class in sample because the defaults use key.getClass().getName();
as the fragment tag, and that's because if you forget the data class
using key.toString()
otherwise then you get very shady process death bugs. So this is a safer default.
In my own projects I never forget data class
so I use data class SomeKey(private val noArgsPlaceHolder: String = ""): FragmentKey()
and then redefine getFragmentTag()
to use toString()
You use show/hide like this right?
Yes.
I used non-data class in sample because the defaults use key.getClass().getName(); as the fragment tag, and that's because if you forget the data class using key.toString() otherwise then you get very shady process death bugs. So this is a safer default. In my own projects I never forget data class so I use data class SomeKey(private val noArgsPlaceHolder: String = ""): FragmentKey() and then redefine getFragmentTag() to use toString()
Yes, I think I did catch something like that.
I was wondering, what are you using in your project? show/hide or attach/detach?
I've used both depending on requirements, haven't ever seen disappearing fragments when the fragment tag and the fragment manager were OK. 🤔
I haven't figured out what could be happening here yet.
I think I got it. The problem is here the animation.
To be sure, I will try invalidate caches and restart, because this gradle build cache sometimes makes me go crazy!
Yep, the animation is the problem.
I disabled completely the animation and now it's working fine with show/hide. Before I was using fade animation for all kind transitions, I guess thats why the fragment was there, but invisible.
Cross-fade should not break, even with show-hide 🤔
If ONLY slide animation is used then it works fine too.
Oh, interesting. Are you using setTransition(TRANSIT_FADE), or setCustomAnimations for the crossfade?
If you use the other variant, can you try the other variant to see if it helps? Sounds like fragmentManager is conflicting with itself. I wonder if this is a Fragment 2.3.x bug...
Looks likes I was wrong about the type of animation, that isn't the problem. Also I don't see any difference between setTransition()
and setCustomAnimations()
.
It depends on which combination of animations I use onForwardNavigation()
, onBackwardNavigation()
, onReplaceNavigation()
. The default animation of DefaultFragmentStateChanger
works correct. But If I mix some animations then I get weird behavior.
For example, if I use fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
for onForwardNavigation()
and onBackwardNavigation()
, but for onReplaceNavigation()
use fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
then on the root fragment of a stack where previously I did get a disappeared screen, I do get I a little bit scaled screen, like it did stop on some step of animation when it was doing the "open" animation.
But if I use for all cases of navigation only TRANSIT_FRAGMENT_FADE
or TRANSIT_FRAGMENT_OPEN
than it works correct.
I'm totally out of ideas, mostly because I vaguely remember having some issues with FragmentManager alpha transitions (FragmentTransaction bug, nothing to do with Simple-Stack) and flickering, and having to manually say view.setVisibility(View.VISIBLE)
at some point, but this used to be fixed as it was back in support-v27.
I think we can close the issue, because the main problem I had was handled. And the part about the animation issue, well, I was planing to remove the animation anyway. But still is a strange behavior.
Thank you for such quick response and help!
I've read the tutorial and have browsed other issues, but didn't find information how to implement such behavior. Or I just missed it.
I need to
setHistory()
with a certain Key, but it is already in backstack, so now it just behaves like I would callgoBack()
.I could just override
getFragmentTag()
by the Key and set an irrelavant value with default value like 0, and when I need to recreated this Key I would setRandom.nextInt()
just to distinguish the 2 Key's, but it's a hack.Am I missing something and there is some reasonable way to get this behavior?