Status Update
Comments
sk...@gmail.com <sk...@gmail.com> #2
reemission of the same liveData is racy
yb...@google.com <yb...@google.com>
b9...@gmail.com <b9...@gmail.com> #3
yb...@google.com <yb...@google.com> #4
yb...@google.com <yb...@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()
}
}
yb...@google.com <yb...@google.com> #6
sk...@gmail.com <sk...@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} )
}
b9...@gmail.com <b9...@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
yb...@google.com <yb...@google.com> #9
it won't make it to the next version (the built was already cut for the postponed Android11 launch). Should go out the version after :) but meanwhile, you can try using the snapshot (androidx.dev). we don't really play w/ this codebase much so it should be fairly stable :)
ap...@google.com <ap...@google.com> #10
Branch: androidx-master-dev
commit 4a302c8fadff7fefa27c7172d77d1128a2fa8f13
Author: Yigit Boyar <yboyar@google.com>
Date: Wed Jun 03 16:53:27 2020
Handle re-entry in live data
This CL fixes a bug where LiveData would not properly handle
re-entry in its onActive method.
There are two cases:
* onActive change method was not handling re-entry, causing
it to possibly make duplicate calls to onActive/inactive.
-> Now we guard this behind a counter to handle re-entry
* dispatch when observer is added would not handle cases where
lifecycle might change state while we are dispatching the value.
-> Now we check for state again after dispatching and if it
changed, we trigger onActive again.
Bug: 157840298
Test: FlowAsLiveDataIntegrationTest, LiveDataTest
Change-Id: I4d368886288a435f65a4db7529d987d0401b25a7
M lifecycle/lifecycle-livedata-core/src/main/java/androidx/lifecycle/LiveData.java
M lifecycle/lifecycle-livedata-core/src/test/java/androidx/lifecycle/LiveDataTest.java
M lifecycle/lifecycle-livedata-ktx/build.gradle
A lifecycle/lifecycle-livedata-ktx/src/androidTest/java/androidx.lifecycle/FlowAsLiveDataIntegrationTest.kt
yb...@google.com <yb...@google.com>
an...@gmail.com <an...@gmail.com> #11
I'm getting this same java.lang.IllegalStateException: Cancel call cannot happen without a maybeRun
exception every so often (on devices running production, but not locally during debug).
Is there some other way I can work around this (besides taking a dependency on androidx.dev)?
I have two StateFlows (The values change based on logic in background Workers)
private val _activeCycleIdFlow = MutableStateFlow(0)
private val _latestCycleIdFlow = MutableStateFlow(0)
whose results are combined
val newCycleAvailable: Flow<Boolean>
get() = _activeCycleIdFlow.combine(_latestCycleIdFlow) { a, b -> a != b }
Which is used as follows:
val newCycle: LiveData<Boolean> = cycleRepo.newCycleAvailable.asLiveData()
yb...@google.com <yb...@google.com> #12
unfortunately i cannot think of an easy way to work around this besides copying the asLiveData
code and removing the exception (it won't hurt actually, it is just consistency check to find such bugs).
Depending on which version you are in, depending on androidx.dev may not be too bad as it fairly stable library. If I were you, i would just pull in my own asLiveData :(
an...@gmail.com <an...@gmail.com> #13
an...@gmail.com <an...@gmail.com> #14
java.lang.IllegalStateException
before emitting? There isn't much else to asLiveData
.
@InternalCoroutinesApi
val newCycle: LiveData<Boolean> = liveData {
cycleRepo.newCycleAvailable
.catch {
// ignore IllegalStateException and log cause
}
.collect {
emit(it)
}
}
yb...@google.com <yb...@google.com> #15
catching exceptions thrown from the pipeline is not a great idea as it might leave it in an inconsistent state (because the code that is intended to run after it won't run). It is better to just copy it w/o the check
an...@gmail.com <an...@gmail.com> #16
Okay, I'm clearly missing something; when I open the code (ctrl+click) for asLiveData
(from FlowLiveData.kt
), it seems very simple, and I don't see any checks. This is it:
@JvmOverloads
fun <T> Flow<T>.asLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT
): LiveData<T> = liveData(context, timeoutInMs) {
collect {
emit(it)
}
}
If I do the following am I not just duplicating the above?
val newCycle: LiveData<Boolean> = liveData {
cycleRepo.newCycleAvailable
.collect {
emit(it)
}
}
an...@gmail.com <an...@gmail.com> #18
Thanks. That makes more sense to me :)
an...@gmail.com <an...@gmail.com> #19
So I changed my code back to using .asLiveData()
and modified my gradle scripts to include
allprojects {
repositories {
...
maven { url 'https://androidx.dev/snapshots/builds/6603247/artifacts/repository' }
}
}
and
def lifecycle_version = "2.3.0-SNAPSHOT"
I compared the CoroutineLiveData.kt
for the different versions (alpha4, snapshot) and they are identical. I take it the fix is elsewhere? Is it publicly available? Sorry I don't normally use snapshot builds of libraries.
yb...@google.com <yb...@google.com> #20
yea the fix is actually in core.
i was recommending just removing the check for now, it won't hurt as it is more of a state check to catch these bugs.
but i'm thinking, maybe you should just move to snapshot. also a new version is coming w/ the fix soon (i think next week)
an...@gmail.com <an...@gmail.com> #21
#20,
Thank you.
fi...@colendi.com <fi...@colendi.com> #22
Does anyone have a suggestion?
Description
Component used:
androidx.lifecycle:lifecycle-livedata-ktx
androidx.lifecycle:lifecycle-runtime
androidx.lifecycle:lifecycle-runtime-ktx
androidx.lifecycle:lifecycle-livedata-ktx
androidx.lifecycle:lifecycle-viewmodel-ktx
androidx.lifecycle:lifecycle-common-java8
Version used: 2.3.0-alpha02
Devices/Android versions reproduced on: OnePlus6T, Samsungs, Xiaomis, etc.
We are using
Flow.asLiveData()
converter. We receivejava.lang.IllegalStateException: Cancel call cannot happen without a maybeRun
exceptions on production. Unable to reproduce locally. Seems like some race condition is happening in LiveData.