Fixed
Status Update
Comments
il...@google.com <il...@google.com> #2
Yigit, do you have time to fix it?
reemission of the same liveData is racy
reemission of the same liveData is racy
yu...@gmail.com <yu...@gmail.com> #3
yea i'll take it.
il...@google.com <il...@google.com>
m....@futuremind.com <m....@futuremind.com> #4
Thanks for the detailed analysis. This may not be an issue anymore since we've started using Main.immediate there but I' not sure; I'll try to create a test case.
co...@protonmail.com <co...@protonmail.com> #5
just emitting same live data reproduces the issue.
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
ap...@google.com <ap...@google.com> #6
With 2.2.0-alpha04 (that use Main.immediate), the issue seems to be still there (I tested it by calling emitSource() twice, like your test case)
jb...@google.com <jb...@google.com> #7
yea sorry immediate does not fix it.
I actually have a WIP fix for it:
https://android-review.googlesource.com/c/platform/frameworks/support/+/1112186
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} )
}
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} )
}
yu...@gmail.com <yu...@gmail.com> #8
Project: platform/frameworks/support
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
https://android-review.googlesource.com/1112186
https://goto.google.com/android-sha1/af12e75e6b4110f48e44ca121466943909de8f06
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
yu...@gmail.com <yu...@gmail.com> #9
So I debugged more using the sample I previously provided and it seems like it's related to this, although it only happens when using flowWithLifecycle as described here:
Attaching the sample that shows the problems and the video.
In sample view model, there is simple flow that emits text in some interval.
In 2.4.0-alpha04 - Collecting flow directly via collectAsState or via rememberFlowWithLifecycle works as expected (interval Flow doesn't complete until the user leaves the screen)
In 2.4.0-alpha05-06 - Screen becomes empty tab reselection
In Snapshot #7634339:
- Tab reselection doesn't cause empty screens.
- Tab reselection doesn't cause early flow completion when collecting interval flow directly via collectAsState
- Tab reselection does cause early flow completion when collecting interval flow wrapped rememberFlowWithLifecycle (as show in attached video)
ro...@gmail.com <ro...@gmail.com> #10
This is really weird but I believe this issue resurfaced in 2.7.1. I was using 2.5.3 and it was working just fine but today i updated the dependency and this started happening.
mi...@gmail.com <mi...@gmail.com> #11
Same for me. I was using 2.7.1. When I selected the arrow to navigate back twice quickly, the app would go back one screen, then the screen would go completely blank. When I reverted to 2.5.3, that issue went away.
so...@gmail.com <so...@gmail.com> #12
Same for me. I was using 2.7.2 and, oh man, when I encountered this issue I didn't even know where to start debugging. Thank god it worked just fine when I downgraded to 2.5.3.
jb...@google.com <jb...@google.com> #13
Please file a new bug with a minimal sample project that reproduces this issue.
mi...@gmail.com <mi...@gmail.com> #14
same here, just updated from 2.5.3 to 2.7.3 and screen is blank when navigating for second time on same screen
de...@gmail.com <de...@gmail.com> #15
To reproduce this issue, I attached a basic navigation project that consists of screens with buttons that go from one Screen to another.
Additionally, I attached two videos. One using Navigation 2.6.0 shows it is working fine, while the other video using Navigation 2.7.1 shows the strange behavior of a blank flash.
I tested all 2.7.x versions and the 2.8.0 alpha, and it's still happening.
Additionally, in some cases, the transition of the screens is that it enters from the upper right corner to the lower left. This behavior is bizarre and erratic since there is no defined animation, and it happens randomly on the screen. Only when many buttons on the screens are pressed quickly.
Feel free to tag me if there is any advance :(. (I am new here, IDK how this works)
Additionally, I attached two videos. One using Navigation 2.6.0 shows it is working fine, while the other video using Navigation 2.7.1 shows the strange behavior of a blank flash.
I tested all 2.7.x versions and the 2.8.0 alpha, and it's still happening.
Additionally, in some cases, the transition of the screens is that it enters from the upper right corner to the lower left. This behavior is bizarre and erratic since there is no defined animation, and it happens randomly on the screen. Only when many buttons on the screens are pressed quickly.
Feel free to tag me if there is any advance :(. (I am new here, IDK how this works)
yu...@gmail.com <yu...@gmail.com> #16
#15 you should report this in a new ticket
ja...@gmail.com <ja...@gmail.com> #17
Here is a solution that works for me. The blank screen seems to happen if there's no screen in the previous history to navigate to when a user double-clicks the back arrow too quickly.
if (navController.previousBackStackEntry != null) {
navController.popBackStack()
}
if (navController.previousBackStackEntry != null) {
navController.popBackStack()
}
ja...@gmail.com <ja...@gmail.com> #18
And here is my solution for bottom navigation, always check if the current route is not equal to the route being navigated to:
onClick = {
if (selectedItemIndex != index) {
localNavController.navigate(
route = item.route,
builder = {
launchSingleTop = true
restoreState = true
popUpTo(localNavController.graph.startDestinationId) {
saveState = true
}
}
)
}
}
onClick = {
if (selectedItemIndex != index) {
localNavController.navigate(
route = item.route,
builder = {
launchSingleTop = true
restoreState = true
popUpTo(localNavController.graph.startDestinationId) {
saveState = true
}
}
)
}
}
Description
Component used: Navigation Compose
Version used: androidx.navigation:navigation-compose:2.4.0-alpha05
Devices/Android versions reproduced on: Android 12 beta
Problem: When re-selecting the same tab (i.e clicking already selected tab), the screen becomes empty. It doesn't happen when current destination is the root graph's startDestination.
I first noticed this on my app, then confirmed it by trying it on github.com/chrisbanes/tivi and upgrading nav compose to 2.4.0-alpha05.