Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extension function to retrieve a Flow of NavBackStackEntries #89

Conversation

simonschiller
Copy link
Contributor

Proposed Changes

  • Added an extension function to retrieve the current NavBackStackEntry as a Flow.

Testing

Test: Added a test for the new function

Issues Fixed

Fixes: 163947280

@dlam dlam requested review from ianhanniballake and jbw0033 and removed request for ianhanniballake October 14, 2020 17:01
.withIndex()
.onEach { (index, backStackEntry) ->
val expectedDestination = index 1
assertEquals(expectedDestination, backStackEntry.destination.id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Truth asserts (note, we already have an androidTest dependency on Truth) over Junit asserts here:

assertThat(backStackEntry.destination.idt).isEqualTo(expectedDestination)

Or preferably use the assertWithMessage() version that includes a more detailed message that is printed when the assert fails.

@dlam dlam removed the request for review from jbw0033 October 15, 2020 09:29
@Suppress("EXPERIMENTAL_API_USAGE")
public fun NavController.getBackStackEntryFlow(): Flow<NavBackStackEntry> = callbackFlow {
val listener = NavController.OnDestinationChangedListener { controller, _, _ ->
controller.currentBackStackEntry?.let(::sendBlocking)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to use second argument instead? given that it is non null it will make things as easy as sendBlocking(destination)

another corner case question: sendBlocking can theoretically block on the main thread, when there is slow consumer and a lot of actions here. Though it seems like fairly theoretical concern

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be possible, but then it would be a Flow<NavDestination> instead of a Flow<NavBackStackEntry>, which is not what we want I guess (as NavBackStackEntry is the class that gives access to things like ViewModelStore and the SavedStateRegistry). But maybe it would make sense to have both, a backStackEntryFlow and a destinationFlow?

Valid point, I also wasn't sure what's best to use here. The other option would be to use offer, which could lead to lost items it the consumer is slow.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are specifically looking for the NavBackStackEntry here, not NavDestination.

* it changes. If there is no active [NavBackStackEntry], no item will be emitted.
*/
@Suppress("EXPERIMENTAL_API_USAGE")
public fun NavController.getBackStackEntryFlow(): Flow<NavBackStackEntry> = callbackFlow {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably suggest to shape it as extension property:
public val NavController.backStackEntryFlow : ....

* Creates and returns a [Flow] that will emit the currently active [NavBackStackEntry] whenever
* it changes. If there is no active [NavBackStackEntry], no item will be emitted.
*/
@Suppress("EXPERIMENTAL_API_USAGE")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be marked as experimental api. We won't be able to release it as stable until callbackFlow will be stable (androidx gives binary compatibility guarantees that could be broken by callbackFlow)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure I understand correctly - since it is part of the public API @ExperimentalCoroutinesApi is required. If it were an internal function, @Suppress would be fine (as it does not cause binary incompatible changes), correct?

@Suppress("EXPERIMENTAL_API_USAGE")
public fun NavController.getBackStackEntryFlow(): Flow<NavBackStackEntry> = callbackFlow {
@ExperimentalCoroutinesApi
public val NavController.backStackEntryFlow: Flow<NavBackStackEntry> get() = callbackFlow {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we change this to NavController.currentBackStackEntryFlow to be consistent with NavController.currentBackStackEntry API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done 👍

@Suppress("EXPERIMENTAL_API_USAGE")
public fun NavController.getBackStackEntryFlow(): Flow<NavBackStackEntry> = callbackFlow {
val listener = NavController.OnDestinationChangedListener { controller, _, _ ->
controller.currentBackStackEntry?.let(::sendBlocking)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are specifically looking for the NavBackStackEntry here, not NavDestination.

@simonschiller
Copy link
Contributor Author

CI is red, but looks unrelated - was this a build flake? Can I retrigger somehow?

@dlam
Copy link
Member

dlam commented Oct 28, 2020

Hey the build was just fixed! Sorry it took a few days to get it landed - could you try rebasing your change on top of androidx-master-dev and see if the tests pass now?

@simonschiller
Copy link
Contributor Author

Rebasing fixed the issue 👍

@ianhanniballake
Copy link
Member

Thanks again for implementing this! It'll become available in Navigation 2.4.0-alpha01.

@simonschiller simonschiller deleted the feature/back-stack-entry-flow branch January 22, 2021 06:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
6 participants