Fixed
Status Update
Comments
il...@google.com <il...@google.com>
ap...@google.com <ap...@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
ap...@google.com <ap...@google.com> #3
yea i'll take it.
ap...@google.com <ap...@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.
ap...@google.com <ap...@google.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)
ap...@google.com <ap...@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} )
}
ap...@google.com <ap...@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
jb...@google.com <jb...@google.com>
il...@google.com <il...@google.com>
ap...@google.com <ap...@google.com> #9
Project: platform/frameworks/support
Branch: androidx-main
commit 08ba745b9fda03c8a6c08b3f5abd4dbcdbf60ff5
Author: Ian Lake <ilake@google.com>
Date: Thu Jun 23 22:56:52 2022
Move target fragment into FragmentState
Co-locate the target fragment's unique identifier
and request code with other library state in the
FragmentState object.
Test: existing tests pass
BUG: 207158202
Change-Id: If7ee5d7729335b1ff3c2fa5d671d698d7aebb433
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
https://android-review.googlesource.com/2134685
Branch: androidx-main
commit 08ba745b9fda03c8a6c08b3f5abd4dbcdbf60ff5
Author: Ian Lake <ilake@google.com>
Date: Thu Jun 23 22:56:52 2022
Move target fragment into FragmentState
Co-locate the target fragment's unique identifier
and request code with other library state in the
FragmentState object.
Test: existing tests pass
BUG: 207158202
Change-Id: If7ee5d7729335b1ff3c2fa5d671d698d7aebb433
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
ap...@google.com <ap...@google.com> #10
Project: platform/frameworks/support
Branch: androidx-main
commit 775876606f25d109a6833503514834b428f7bb1e
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 00:05:17 2022
Move Fragment savedInstanceState out of FragmentState
Rather than FragmentState having a mix of
library state and user saved state (i.e., the state
returned by onSaveInstanceState()), these should be
stored independently from one another.
Test: existing tests pass
BUG: 207158202
Change-Id: If158c0e860aa7463252bc179673658b7696c3371
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
https://android-review.googlesource.com/2134687
Branch: androidx-main
commit 775876606f25d109a6833503514834b428f7bb1e
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 00:05:17 2022
Move Fragment savedInstanceState out of FragmentState
Rather than FragmentState having a mix of
library state and user saved state (i.e., the state
returned by onSaveInstanceState()), these should be
stored independently from one another.
Test: existing tests pass
BUG: 207158202
Change-Id: If158c0e860aa7463252bc179673658b7696c3371
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
ap...@google.com <ap...@google.com> #11
Project: platform/frameworks/support
Branch: androidx-main
commit bf62dd252aae22511da44fc8bb4975e57abedfa3
Author: Ian Lake <ilake@google.com>
Date: Thu Jun 23 23:07:37 2022
Move user visible hint into FragmentState
Co-locate the userVisibleHint flag with the
other library state in the FragmentState object.
Test: existing tests pass
BUG: 207158202
Change-Id: I8bdd5ee138aa1d6505df9e806635eb78bca69729
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
https://android-review.googlesource.com/2134686
Branch: androidx-main
commit bf62dd252aae22511da44fc8bb4975e57abedfa3
Author: Ian Lake <ilake@google.com>
Date: Thu Jun 23 23:07:37 2022
Move user visible hint into FragmentState
Co-locate the userVisibleHint flag with the
other library state in the FragmentState object.
Test: existing tests pass
BUG: 207158202
Change-Id: I8bdd5ee138aa1d6505df9e806635eb78bca69729
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
ap...@google.com <ap...@google.com> #12
Project: platform/frameworks/support
Branch: androidx-main
commit 1deb87b58f32ad191ba066ab5d48740d45c95464
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 17:53:01 2022
Move Fragment View State out of savedInstanceState Bundle
Rather than include the Fragment's SparseArray<Parcelable>
of its view's state or the Fragment View's SavedStateRegistry
bundle as part of the Bundle returned by onSaveInstanceState,
store those as separate values in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I3abfc7db186e6a921b00193fff27c62199687976
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
https://android-review.googlesource.com/2135874
Branch: androidx-main
commit 1deb87b58f32ad191ba066ab5d48740d45c95464
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 17:53:01 2022
Move Fragment View State out of savedInstanceState Bundle
Rather than include the Fragment's SparseArray<Parcelable>
of its view's state or the Fragment View's SavedStateRegistry
bundle as part of the Bundle returned by onSaveInstanceState,
store those as separate values in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I3abfc7db186e6a921b00193fff27c62199687976
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
ap...@google.com <ap...@google.com> #13
Project: platform/frameworks/support
Branch: androidx-main
commit 8a019327ad267d6251167e400ea79cb8a54243b3
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 20:53:15 2022
Move childFragmentManager state out of savedInstanceState
Migrate the childFragmentManager state out of the same
Bundle as is passed to onSaveInstanceState(). Instead,
store that Bundle as a separate value in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I456259053dfc833d39c4f648e23735b98cb65714
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
https://android-review.googlesource.com/2135877
Branch: androidx-main
commit 8a019327ad267d6251167e400ea79cb8a54243b3
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 20:53:15 2022
Move childFragmentManager state out of savedInstanceState
Migrate the childFragmentManager state out of the same
Bundle as is passed to onSaveInstanceState(). Instead,
store that Bundle as a separate value in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I456259053dfc833d39c4f648e23735b98cb65714
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
ap...@google.com <ap...@google.com> #14
Project: platform/frameworks/support
Branch: androidx-main
commit 3ccf9b6e609c6f2130689bb2f8c4bff6e2907df3
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:38:19 2022
Use all initial state when saving an initializing fragment
With the state split across multiple fields, saving the
state of an Fragment still in the INITIALIZING state should
use the entire saved state Bundle set by
setInitialSavedState() rather than only extracting the
onSaveInstanceState() bundle out of it.
Test: existing tests pass
BUG: 207158202
Change-Id: I95868473b28b179d7cc0b0e606427928982dc96c
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
https://android-review.googlesource.com/2135880
Branch: androidx-main
commit 3ccf9b6e609c6f2130689bb2f8c4bff6e2907df3
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:38:19 2022
Use all initial state when saving an initializing fragment
With the state split across multiple fields, saving the
state of an Fragment still in the INITIALIZING state should
use the entire saved state Bundle set by
setInitialSavedState() rather than only extracting the
onSaveInstanceState() bundle out of it.
Test: existing tests pass
BUG: 207158202
Change-Id: I95868473b28b179d7cc0b0e606427928982dc96c
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #15
Project: platform/frameworks/support
Branch: androidx-main
commit f7ec0cc1786b4a16c0569cc07ecf5093693bcab0
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:30:15 2022
Skip empty/null keys when saving Fragment state
Each key in the Fragment's saved state Bundle takes up
space in the limited resource that is the total
saved instance state. By removing empty or null keys,
we can ensure that the set of saved key/values is
minimized.
Test: existing tests pass
BUG: 207158202
Change-Id: I4e0f4772982406bfe10e64d78d26e93f4e2bc387
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
https://android-review.googlesource.com/2135879
Branch: androidx-main
commit f7ec0cc1786b4a16c0569cc07ecf5093693bcab0
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:30:15 2022
Skip empty/null keys when saving Fragment state
Each key in the Fragment's saved state Bundle takes up
space in the limited resource that is the total
saved instance state. By removing empty or null keys,
we can ensure that the set of saved key/values is
minimized.
Test: existing tests pass
BUG: 207158202
Change-Id: I4e0f4772982406bfe10e64d78d26e93f4e2bc387
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
ap...@google.com <ap...@google.com> #16
Project: platform/frameworks/support
Branch: androidx-main
commit 5cc7478b61c2f48452770285d7ba8c74be907b19
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:18:57 2022
Move SavedStateRegistry state out of savedInstanceState
Migrate the SavedStateRegistry's state out of the same
Bundle as is passed to onSaveInstanceState(). Instead,
store that Bundle as a separate value in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I903d56901e6c5a5caf2890a4dbe5471c73169b56
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
https://android-review.googlesource.com/2135878
Branch: androidx-main
commit 5cc7478b61c2f48452770285d7ba8c74be907b19
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:18:57 2022
Move SavedStateRegistry state out of savedInstanceState
Migrate the SavedStateRegistry's state out of the same
Bundle as is passed to onSaveInstanceState(). Instead,
store that Bundle as a separate value in the Fragment's
saved state Bundle.
Test: existing tests pass
BUG: 207158202
Change-Id: I903d56901e6c5a5caf2890a4dbe5471c73169b56
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
ap...@google.com <ap...@google.com> #17
Project: platform/frameworks/support
Branch: androidx-main
commit 28e7a78343af524c7854a3f951809448a8457dd1
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:58:43 2022
Move and rename _TAG constants to _KEY
Rename all constants used as Bundle keys to use
the _KEY suffix rather than _TAG to prevent mistaking
them for debug tags.
Also moves all keys associated with the Fragment's state
into FragmentStateManager, which is responsible for
saving the Fragment's state. Keys associated with saving
the FragmentManager's state are still in FragmentManager.
Test: existing tests pass
BUG: 207158202
Change-Id: I6e47a4a0ec84c708f9a3c984e737ed7314530156
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
https://android-review.googlesource.com/2135883
Branch: androidx-main
commit 28e7a78343af524c7854a3f951809448a8457dd1
Author: Ian Lake <ilake@google.com>
Date: Fri Jun 24 21:58:43 2022
Move and rename _TAG constants to _KEY
Rename all constants used as Bundle keys to use
the _KEY suffix rather than _TAG to prevent mistaking
them for debug tags.
Also moves all keys associated with the Fragment's state
into FragmentStateManager, which is responsible for
saving the Fragment's state. Keys associated with saving
the FragmentManager's state are still in FragmentManager.
Test: existing tests pass
BUG: 207158202
Change-Id: I6e47a4a0ec84c708f9a3c984e737ed7314530156
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
M fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
M fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
M fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
il...@google.com <il...@google.com> #18
The saved state of Fragments has been split entirely between private library state (custom Parcelable
classes) and state provided by you, the developer, which is now always stored in a Bundle
that allows determining exactly which part of the fragment's state is too large.
The final structure is as follows:
In the Activity's onSaveInstanceState
, the "android:support:fragments"
key now contains a Bundle that contains the following information:
"state"
- the privateParcelable
storing theFragmentManager
's saved state (e.g., the fragment back stack info)- For each
that has been set viaFragment Result setFragmentResult
but has not yet been delivered:"result_$name"
-> (user defined Bundle) - For each Fragment (where the
fragment_id
matches the UUIDs found in the ):debug logging "fragment_$fragment_id"
-> Bundle"state"
-> the privateParcelable
storing theFragment
's saved state (e.g., the class name, max lifecycle, etc.)"arguments"
-> (Bundle of arguments)"savedInstanceState"
-> (onSaveInstanceState
filled Bundle)"registryState"
-> (SavedStateRegistry
filled Bundle)"childFragmentManager"
-> The “android:support:fragments” equivalent Bundle of the childFragmentManager
, which would lead us recursively down the tree"viewState"
-> theSparseArray<Parcelable>
returned byView.saveHierarchyState
representing theFragment View state "viewRegistryState"
-> (ViewSavedStateRegistry
filled Bundle)
This will be fully available in Fragment 1.6.0-alpha01.
Description
Component used: Fragment
Version used: 1.4.0
There are tools like toolargetool that let you explore what is taking up space in your saved instance state. However, it has no visibility into custom Parcelables like the
FragmentManagerState
used to store the entire FragmentManager's hierarchy of saved state.This makes it hard to differentiate between the state of the FragmentManager itself and the state of each individual fragment, and, within a particular fragment, differentiating the view state, arguments, state provided by
onSaveInstanceState()
, and the fragment'sSavedStateRegistry
.Therefore the focus should be on exposing the hierarchy of fragments - the bookkeeping associated with an individual Fragment and the FragmentManager specific state can and should remain as separate Parcelable instances that don't expose their internal fields.