In `Nav3`, is there any timing guarantee after cha...
# compose
u
In
Nav3
, is there any timing guarantee after changing the backstack? Say I
Copy code
backstack.add(DetailNavKey)
Can I reason WHEN will the
DetailNavEntry
in composition? Or, is the only guarantee "eventually"? (I'm asking in context of process restore & sending events - whether I can get away with
MutableSharedFlow
or do I need a randevouz
Channel
where sender would wait for the receiver (nav entry) to come online?
e
Can you explain what you are actually trying to do? No solutions for now just requirements
u
Sending a "payment successful" event to a existing screen that came as a intent deeplink (from browser) - and the specific case is also during process restore, as the app might have been killed since browser is different app and now the backstack is being restored and i want to know when can I expect respective nav entries to come back only (to collec the event)
e
Okay understood. There is no specific “when” but my recommendation would be a simple setup like: • App/Activity-scoped component (like a`ViewModel` or
Retained
) that will hold the (possibly observable) data holder. The code that will receive & parse the intent will directly update this data holder. • NavEntryDecorator that “connects” the particular entry to the above component, as long as the entry is in the backstack. This means when the entry is composed you can getOrCreate your data holder and, eventually, clear it when the entry is popped off the backstack.
u
Well that's essentially the Channel way What I don't like about this approach is that these caches don't invalidate, what if in some weird case the entry won't be there etc, next nav entry might get other's entries event etc
e
next nav entry might get other’s entries event
Should not be possible as the data holder should be specific per entry (based on the content key passed to the decorator for instance)
u
what if the nav key is param-less, like
data object PaymentOptions : NavKey
anyways, I know there's ways but they're just inferior to what we had before compose nav tldr; it seems it's impossible to get fire-and-forget semantics that are process restore safe 😕
e
Content Keys have to be unique so parameterless or not if they dont have different content keys they are the same entry UI
Process death is the system literally killing your process, if your data is not stored “somewhere” then its gone 😅. There has never been a way to “fire & forget” anything when it comes to process death. All you can do is stash small data away in a bundle and get it back later. Everything else is just getting creative with those capabilities.
> what we had before compose nav I am not sure I follow, how was this better before compose nav3 🤔? I cant think of anything that was possible before that isnt now
u
What I meant in Fragments/Conductor after activity onCreate / router init, you were guaranteed that the frag. manager / router is already restored after process death/restore Now you're only guaranteed bacstack keys list is restored after rememberNavBackStack which by it self means nothing in terms of reasoning whats initialized
So afterwards you could send a fire and forget event / callback knowing if logically its supposed to be there, it will be there
> Content Keys have to be unique so parameterless or not Do you literally attach random uuids to everything?
e
Fragments (and the FragmentManager) did a lot of the heavy lifting for you. I understand your point though. I think its not worth it to compare as they are quite different (same difference as compose UI vs Xml/Views). Anyways, you can always use compose fragment interop and still get the same behavior if its important to you.
Do you literally attach random uuids to everything?
No, the default toString is good enough for majority of cases. Unless you are intentionally overriding toString to provide the same string for different navKeys, most keys will have different contentKeys meaning you can have unique data holders for each screen.
u
so about the payment event to payment options screen how exactly would you avoid sending the event to the "wrong" instance? I dont have a way of passing some piece of state all the way around the payment loop and have it be present on the deeplink 😕
e
What do you mean wrong instance? 🤔 In your app do you have multiple payment options screens with the exact same nav key on the back stack at the same time?
If there is just one screen, then the deep link that opens the browser can include some token that the browser should call back with. That token can be mapped to your content key in the app (mapping will be in remember saveable so it also survives process death) and after the return intent is fired, you can map the token back to a content key then to the actual data holder.
u
No, logically there is just one, but you're caching the event, in order for the payment screen "which logically is already there", but practically it async so not yet to receive it, but you're not guaranteed it will, something COULD happen and it will not come up, now event is cached forever, and then next "session" user opens the screen it will autocollect the cached event
basically the cache is architecture nonsense, it's just to bridge over the stupid asyncness of compose navigation and now you gotta deal with cache invalidation unless you can attribute the event to the concrete "instance" of a screen somehow
e
You realize fragments work the exact same way right? Fragment results are also cached by the fragment manager, pending when a fragment with the right TAG is added back to the Fragment Manager. Its just already handled for you.