Fixed
Status Update
Comments
se...@google.com <se...@google.com> #2
Building note: run ./gradlew ... -x processReleaseMetadata
yb...@google.com <yb...@google.com> #3
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 5f6e46e40a7e47924ac1d04426230466de7b6f38
Author: Sergey Vasilinets <sergeyv@google.com>
Date: Tue Aug 07 15:57:10 2018
Fix ViewModel proguard rules
It removes allowshrinking modifier: a constructor
shouldn't be removed if it is unused, because it is
called through reflection
Test: manual =\
bug: 112230489
Change-Id: I215fe895fa12eb04172e9380a296e2d74567907c
M lifecycle/viewmodel/proguard-rules.pro
https://android-review.googlesource.com/727573
https://goto.google.com/android-sha1/5f6e46e40a7e47924ac1d04426230466de7b6f38
Branch: androidx-master-dev
commit 5f6e46e40a7e47924ac1d04426230466de7b6f38
Author: Sergey Vasilinets <sergeyv@google.com>
Date: Tue Aug 07 15:57:10 2018
Fix ViewModel proguard rules
It removes allowshrinking modifier: a constructor
shouldn't be removed if it is unused, because it is
called through reflection
Test: manual =\
bug: 112230489
Change-Id: I215fe895fa12eb04172e9380a296e2d74567907c
M lifecycle/viewmodel/proguard-rules.pro
yb...@google.com <yb...@google.com> #4
Thanks!
yb...@google.com <yb...@google.com> #5
I had the similar problem. Hoping the problem will be fixed in the next release. Thank team!
da...@gmail.com <da...@gmail.com> #6
it will be part of rc02
yb...@google.com <yb...@google.com> #7
When will rc02 be released?
Description
Version used: 2.2.0-alpha01
Devices/Android versions reproduced on: Android 9
I'm having some random crashes due to CoroutineLiveData
```
Fatal Exception: java.lang.IllegalArgumentException: This source was already added with the different observer
at androidx.lifecycle.MediatorLiveData.addSource + 89(MediatorLiveData.java:89)
at androidx.lifecycle.CoroutineLiveDataKt.addDisposableSource + 102(CoroutineLiveDataKt.java:102)
at androidx.lifecycle.CoroutineLiveData.emitSource$lifecycle_livedata_ktx_release + 200(CoroutineLiveData.java:200)
at androidx.lifecycle.LiveDataScopeImpl$emitSource$2.invokeSuspend + 89(LiveDataScopeImpl.java:89)
at androidx.lifecycle.LiveDataScopeImpl$emitSource$2.invoke(LiveDataScopeImpl.java:11)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn + 91(UndispatchedKt.java:91)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext + 156(BuildersKt__Builders_commonKt.java:156)
at kotlinx.coroutines.BuildersKt.withContext + 1(BuildersKt.java:1)
at androidx.lifecycle.LiveDataScopeImpl.emitSource + 88(LiveDataScopeImpl.java:88)
at com.geekorum.ttrss.articles_list.FeedsViewModel$refreshed$1.invokeSuspend + 90(FeedsViewModel.java:90)
at com.geekorum.ttrss.articles_list.FeedsViewModel$refreshed$1.invoke(FeedsViewModel.java:8)
at androidx.lifecycle.BlockRunner$maybeRun$1.invokeSuspend + 147(BlockRunner.java:147)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith + 33(BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run + 241(DispatchedTask.java:241)
at android.os.Handler.handleCallback + 873(Handler.java:873)
at android.os.Handler.dispatchMessage + 99(Handler.java:99)
at android.os.Looper.loop + 193(Looper.java:193)
at android.app.ActivityThread.main + 6898(ActivityThread.java:6898)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run + 537(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main + 858(ZygoteInit.java:858)
```
From what I understand of CoroutineLiveData source code, when calling `LiveDataScope.emitSource()` the previous source is removed before adding the new one on MediatorLiveData.
```
@MainThread
internal fun emitSource(source: LiveData<T>): DisposableHandle {
clearSource()
val newSource = addDisposableSource(source)
emittedSource = newSource
return newSource
}
```
However the removing is done by launching a new coroutine
```
internal fun <T> MediatorLiveData<T>.addDisposableSource(
source: LiveData<T>
): DisposableHandle {
val disposed = AtomicBoolean(false)
addSource(source) {
if (!disposed.get()) {
value = it
} else {
removeSource(source)
}
}
return object : DisposableHandle {
override fun dispose() {
if (disposed.compareAndSet(false, true)) {
CoroutineScope(Dispatchers.Main).launch {
removeSource(source)
}
}
}
}
}
```
So there is no guarantee that `MediatorLiveData.addSource()` will be called after the removing coroutine is executed. This leads to the IllegalArgumentException in `MediatorLiveData.addSource()`
```
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
```