I'm a situation where I want my view model to communicate a navigation event to the composition after completing some suspending work. For example, user types in a password, hits "login", and then the backend does some long-running work to do all the things necessary for authentication. My concerns are the following:
• How to represent the nav event as part of the UI state. Simply setting a state property to "loginComplete = true" means it will be true still when the user navigates back (for whatever reason).
• How to reliably cancel the work when the user leaves the composition, but not when the user changes orientations. For example, while the sign-in is happening, the user could press the back button, or navigate into an account recovery screen. If the user does either of these, I want any current sign-in activity to cancel (as opposed to it continuing while the user is off-screen). Navigating back should do this automatically by killing the view model scope, but navigating to the recovery screen doesn't do this.
The sign-in can yield theoretically 3 results: normal success, verification required (nav to a verification screen), or sign in failed. While the sign-in is happening, I also want the UI state to be in a loading state.
Specifically, my questions are:
1. What is best practice for cancelling any jobs/producers in the view model when navigating from a screen, without doing this on configuration changes and the like. I know of the
Activity.isChangingConfigurations
property, but is this reliable? Or should I just make sure to add a call to cancel jobs at every point where a navigation event happens, and make sure no navigation events happen higher up in the composition hierarchy?
2. What is the best practice for the view model communicating a nav event to the composable? I have a single UI state object for each screen, should I include a "nav event" property in the UI state? And how can I ensure this nav event only triggers up to one actual navigation event? I was thinking of creating an object which is like a "OneShotEvent" object, which has a "consume" method that suspends, and only consumes events that weren't already consumed. Or would a SharedFlow with no replay cache, or some application of producer channels be more idiomatic?