Fixed
Status Update
Comments
vi...@google.com <vi...@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
cc...@google.com <cc...@google.com> #3
yea i'll take it.
du...@google.com <du...@google.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.
an...@gmail.com <an...@gmail.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()
}
}
du...@google.com <du...@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)
cl...@gmail.com <cl...@gmail.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} )
}
du...@google.com <du...@google.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
cl...@gmail.com <cl...@gmail.com> #9
Got it! Thanks.
ap...@google.com <ap...@google.com> #10
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 5ac03b4d8c4a234d8c91aecb03361d8d1b856ad3
Author: Clara F <clarafok3@gmail.com>
Date: Thu Nov 19 21:07:43 2020
[GH] A PagingSource Factory that can be invalidated
## Proposed Changes
A PagingSource Factory that stores references to PagingSources for PagingSource invalidation
## Testing
Test: ./gradlew paging:paging-common:test
This is an imported pull request fromhttps://github.com/androidx/androidx/pull/98 .
Resolves #98
Github-Pr-Head-Sha: 63d2bc166414d4b5134ba1dd5998a2a175ccbe25
GitOrigin-RevId: 037f4fe9037bd1aa255a212091f5b955fe9e4693
Fixes: 160716447
Relnote: "A new abstract class InvalidatingPagingSourceFactory has been added
with an `.invalidate()` API that forwards invalidate to all of the PagingSources
it emits"
Change-Id: Ie71fc1cc974dbc72f42572234ea9053e31b44039
M paging/common/api/current.txt
M paging/common/api/public_plus_experimental_current.txt
M paging/common/api/restricted_current.txt
A paging/common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt
A paging/common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt
https://android-review.googlesource.com/1506419
Branch: androidx-master-dev
commit 5ac03b4d8c4a234d8c91aecb03361d8d1b856ad3
Author: Clara F <clarafok3@gmail.com>
Date: Thu Nov 19 21:07:43 2020
[GH] A PagingSource Factory that can be invalidated
## Proposed Changes
A PagingSource Factory that stores references to PagingSources for PagingSource invalidation
## Testing
Test: ./gradlew paging:paging-common:test
This is an imported pull request from
Resolves #98
Github-Pr-Head-Sha: 63d2bc166414d4b5134ba1dd5998a2a175ccbe25
GitOrigin-RevId: 037f4fe9037bd1aa255a212091f5b955fe9e4693
Fixes: 160716447
Relnote: "A new abstract class InvalidatingPagingSourceFactory has been added
with an `.invalidate()` API that forwards invalidate to all of the PagingSources
it emits"
Change-Id: Ie71fc1cc974dbc72f42572234ea9053e31b44039
M paging/common/api/current.txt
M paging/common/api/public_plus_experimental_current.txt
M paging/common/api/restricted_current.txt
A paging/common/src/main/kotlin/androidx/paging/InvalidatingPagingSourceFactory.kt
A paging/common/src/test/kotlin/androidx/paging/InvalidatingPagingSourceFactoryTest.kt
Description
Artifact used: androidx.paging:paging-runtime & rxjava2 Version used: 3.0.0-alpha02
In order to call
pagingSource.invalidate()
to deal with the user of my app deleting a row from the paged RV they're looking at, I had to do the following in my ViewModel:Then, elsewhere in the VM I have a reference to the source to call
invalidate
. This feels really, really ugly. I'm aware that I have to pass a factory intoPager
because it can get recreated, but this feels like it's not something I should really have to worry about.It's hard to say what I would prefer, which is why I imagine it's like this!
Keeping a reference to the
Pager
feels less gross than it does forPagingSource
. PerhapsPager
could internally keep a reference to the existingPagingSource
so I could just callPager.invalidate()
and it would do a similar hack internally?Very happy for better or other suggestions. Currently it feels very awkward, and it was super hard to discover that the
.invalidate()
method even existed to call!