Status Update
Comments
ti...@google.com <ti...@google.com> #2
reemission of the same liveData is racy
qu...@gmail.com <qu...@gmail.com> #3
ti...@google.com <ti...@google.com> #4
ma...@google.com <ma...@google.com> #5
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
lp...@google.com <lp...@google.com> #6
qu...@gmail.com <qu...@gmail.com> #7
I actually have a WIP fix for it:
if your case is the one i found (emitting same LiveData multiple times, as shown in #5) you can work around it by adding a dummy transformation.
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData.map {it })
emitSource(subLiveData.map {it} )
}
ma...@gmail.com <ma...@gmail.com> #8
Branch: androidx-master-dev
commit af12e75e6b4110f48e44ca121466943909de8f06
Author: Yigit Boyar <yboyar@google.com>
Date: Tue Sep 03 12:58:11 2019
Fix coroutine livedata race condition
This CL fixes a bug in liveData builder where emitting same
LiveData source twice would make it crash because the second
emission registry could possibly happen before first one is
removed as source.
We fix it by using a suspending dispose function. It does feel
a bit hacky but we cannot make DisposableHandle.dispose async
and we do not want to block there. This does not mean that there
is a problem if developer disposes it manually since our emit
functions take care of making sure it disposes (and there is
no other way to add source to the underlying MediatorLiveData)
Bug: 140249349
Test: BuildLiveDataTest#raceTest_*
Change-Id: I0b464c242a583da4669af195cf2504e2adc4de40
M lifecycle/lifecycle-livedata-ktx/api/2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/current.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_current.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_current.txt
M lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
M lifecycle/lifecycle-livedata-ktx/src/test/java/androidx/lifecycle/BuildLiveDataTest.kt
an...@google.com <an...@google.com> #9
The issue is inside NavHost.
val modifier = Modifier.padding(padding)
NavHost(navController, startDestination = FIRST_SCREEN) {
composable(FIRST_SCREEN) {
MyScreen(modifier, Color.Blue) {
navController.navigate(SECOND_SCREEN)
}
}
composable(SECOND_SCREEN) {
MyScreen(modifier, Color.Red) {
navController.navigate(FIRST_SCREEN)
}
}
}
When the size has been changed the first line is recomposed and the new modifier object is constructed. Then NavHost is reinvoked with a new builder which contains new lambdas which captures a new modifier. But currently NavHost is not supporting nav graph updates so the new lambdas are ignored. As a result we end up using the initial value of the captured modifier object forever which had size 0. The current workaround would be something like
val modifier = rememberUpdatedState(Modifier.padding(padding))
NavHost(navController, startDestination = FIRST_SCREEN) {
composable(FIRST_SCREEN) {
MyScreen(modifier.value, Color.Blue) {
navController.navigate(SECOND_SCREEN)
}
}
composable(SECOND_SCREEN) {
MyScreen(modifier.value, Color.Red) {
navController.navigate(FIRST_SCREEN)
}
}
}
In this case we wrap the value inside the state object so we can update the state and the old lambda would still use the correct modifier.
Jeremy, assigning it to you as the only correct solution is to support graph updates
an...@google.com <an...@google.com> #11
qu...@gmail.com <qu...@gmail.com> #12
an...@google.com <an...@google.com> #13
qu...@gmail.com <qu...@gmail.com> #14
Alright. I guess this would hit two issues at the same time then. Thank you!
il...@google.com <il...@google.com> #15
Note that if you want to pad in all screens, you should passing the padding directly to NavHost
rather than manually to each screen:
) { padding ->
NavHost(navController, startDestination = FIRST_SCREEN, Modifier.padding(padding)) {
composable(FIRST_SCREEN) {
MyScreen(Color.Blue) {
navController.navigate(SECOND_SCREEN)
}
}
composable(SECOND_SCREEN) {
MyScreen(Color.Red) {
navController.navigate(FIRST_SCREEN)
}
}
}
}
}
This was made possible in
ap...@google.com <ap...@google.com> #16
Branch: androidx-main
commit 294e5e2a1f2933cb927f9ad2bdd7763923295f49
Author: Jeremy Woods <jbwoods@google.com>
Date: Mon Jun 21 14:15:54 2021
Override equals in NavGraph and NavDestinations
Instead of relying on the default equals() behavior that requires
NavGraphs and NavDestinations to be the exact instance to be
considered equal, we should specifically define equals to be objects
with the same values, even if they instances are not exactly the same.
RelNote: "`NavGraph` and `NavDestination`s now override the equals method so
two objects with the same values will be considered equal."
Test: NavGraphTest and NavDestinationAndroidTest
Bug: 175392262
Change-Id: I166eb54122cabc12cc569daea8eefcf8e0ec95a7
M navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationAndroidTest.kt
M navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.kt
M navigation/navigation-common/src/main/java/androidx/navigation/NavDestination.kt
M navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
M navigation/navigation-common/src/test/java/androidx/navigation/NavGraphTest.kt
M navigation/navigation-dynamic-features-fragment/src/main/java/androidx/navigation/dynamicfeatures/fragment/DynamicFragmentNavigator.kt
M navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicActivityNavigator.kt
M navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicGraphNavigator.kt
M navigation/navigation-dynamic-features-runtime/src/main/java/androidx/navigation/dynamicfeatures/DynamicIncludeGraphNavigator.kt
M navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/DialogFragmentNavigator.kt
M navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigator.kt
M navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
ap...@google.com <ap...@google.com> #17
Branch: androidx-main
commit 5e187e759d673ea9c45d7fafe8e98260fe090bd4
Author: Jeremy Woods <jbwoods@google.com>
Date: Wed Jun 23 13:30:16 2021
Allow the NavGraph to be changed in NavHost
Since NavGraph now implements its own equals based on the data in the
graph rather than the instance, we can stop always remembering the
NavGraph and allow it to be changed on recompose.
RelNote: "You can now make changes to the graph of a NavHost. Graphs
with the same startDestination and destinations in the graph will be
considered equal and will not clear the navController back stack."
Test: setSameGraph
Bug: 175392262
Change-Id: I0b8dbcea4186232c3280c4a43be11e4fafcc6ce3
M navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
M navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
M navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
jb...@google.com <jb...@google.com> #18
This has been fixed internally and will be part of the Navigation 2.4.0-alpha05
release.
Description
Jetpack Compose release version: 1.0.0-alpha08 Android Studio Build: Android Studio Arctic Fox | 2020.3.1 Canary 2
BottomBar no longer updates Scaffold's contentPadding whenever bottomBar changes "visibility".
Here is the sample code to reproduce: