diff --git a/app/build.gradle b/app/build.gradle index c1baa709ae..70829b2509 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -221,7 +221,8 @@ dependencies { def lbm_version = "1.0.0" def swiperefresh_version = "1.2.0-alpha01" def documentfile_version = "1.0.1" - def lifecycle_version = "2.2.0" // 2.3.0-alpha07 + def lifecycle_version = "2.3.0-alpha07" + def lifecycle_extensions_version = "2.2.0" def sqlite_version = "2.1.0" def room_version = "2.2.5" // 2.3.0-alpha02 def paging_version = "2.1.2" // 3.0.0-alpha03 @@ -292,9 +293,15 @@ dependencies { // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-runtime // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-livedata // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-livedata-core - implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" + // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-compiler + implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata-core:$lifecycle_version" annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" + // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-extensions + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_extensions_version" + // https://mvnrepository.com/artifact/androidx.room/room-runtime implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-common:$room_version" // because of exclude diff --git a/app/src/main/java/androidx/lifecycle/LiveData.java b/app/src/main/java/androidx/lifecycle/LiveData.java index 719c8edf57..a694fcd9c8 100644 --- a/app/src/main/java/androidx/lifecycle/LiveData.java +++ b/app/src/main/java/androidx/lifecycle/LiveData.java @@ -69,6 +69,8 @@ public abstract class LiveData { // how many observers are in active state @SuppressWarnings("WeakerAccess") /* synthetic access */ int mActiveCount = 0; + // to handle active/inactive reentry, we guard with this boolean + private boolean mChangingActiveState; private volatile Object mData; // when setData is called, we set the pending data and actual data swap happens on the main // thread @@ -329,7 +331,7 @@ public abstract class LiveData { } /** - * Called when the number of active observers change to 1 from 0. + * Called when the number of active observers change from 0 to 1. *

* This callback can be used to know that this LiveData is being used thus should be kept * up to date. @@ -371,6 +373,30 @@ public abstract class LiveData { return mActiveCount > 0; } + @MainThread + void changeActiveCounter(int change) { + int previousActiveCount = mActiveCount; + mActiveCount += change; + if (mChangingActiveState) { + return; + } + mChangingActiveState = true; + try { + while (previousActiveCount != mActiveCount) { + boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0; + boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0; + previousActiveCount = mActiveCount; + if (needToCallActive) { + onActive(); + } else if (needToCallInactive) { + onInactive(); + } + } + } finally { + mChangingActiveState = false; + } + } + class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; @@ -388,11 +414,17 @@ public abstract class LiveData { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { - if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { + Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState(); + if (currentState == DESTROYED) { removeObserver(mObserver); return; } - activeStateChanged(shouldBeActive()); + Lifecycle.State prevState = null; + while (prevState != currentState) { + prevState = currentState; + activeStateChanged(shouldBeActive()); + currentState = mOwner.getLifecycle().getCurrentState(); + } } @Override @@ -431,14 +463,7 @@ public abstract class LiveData { // immediately set active state, so we'd never dispatch anything to inactive // owner mActive = newActive; - boolean wasInactive = LiveData.this.mActiveCount == 0; - LiveData.this.mActiveCount += mActive ? 1 : -1; - if (wasInactive && mActive) { - onActive(); - } - if (LiveData.this.mActiveCount == 0 && !mActive) { - onInactive(); - } + changeActiveCounter(mActive ? 1 : -1); if (mActive) { dispatchingValue(this); } diff --git a/app/src/main/java/androidx/lifecycle/Transformations.java b/app/src/main/java/androidx/lifecycle/Transformations.java index 10261e9352..f687e65c8d 100644 --- a/app/src/main/java/androidx/lifecycle/Transformations.java +++ b/app/src/main/java/androidx/lifecycle/Transformations.java @@ -47,8 +47,8 @@ public class Transformations { * {@code LiveData} containing their full name as a {@code String}. * *

-     * LiveData userLiveData = ...;
-     * LiveData userFullNameLiveData =
+     * LiveData<User> userLiveData = ...;
+     * LiveData<String> userFullNameLiveData =
      *     Transformations.map(
      *         userLiveData,
      *         user -> user.firstName + user.lastName);
@@ -106,9 +106,9 @@ public class Transformations {
      *
      * 
      * class UserViewModel extends AndroidViewModel {
-     *     MutableLiveData nameQueryLiveData = ...
+     *     MutableLiveData<String> nameQueryLiveData = ...
      *
-     *     LiveData> getUsersWithNameLiveData() {
+     *     LiveData<List<String>> getUsersWithNameLiveData() {
      *         return Transformations.switchMap(
      *             nameQueryLiveData,
      *                 name -> myDataSource.getUsersWithNameLiveData(name));