Home | History | Annotate | Download | only in lifecycle
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.lifecycle;
     18 
     19 import static androidx.lifecycle.Lifecycle.State.DESTROYED;
     20 import static androidx.lifecycle.Lifecycle.State.STARTED;
     21 
     22 import androidx.annotation.MainThread;
     23 import androidx.annotation.NonNull;
     24 import androidx.annotation.Nullable;
     25 import androidx.arch.core.internal.SafeIterableMap;
     26 import androidx.arch.core.executor.ArchTaskExecutor;
     27 
     28 import java.util.Iterator;
     29 import java.util.Map;
     30 
     31 /**
     32  * LiveData is a data holder class that can be observed within a given lifecycle.
     33  * This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
     34  * this observer will be notified about modifications of the wrapped data only if the paired
     35  * LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
     36  * {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}. An observer added via
     37  * {@link #observeForever(Observer)} is considered as always active and thus will be always notified
     38  * about modifications. For those observers, you should manually call
     39  * {@link #removeObserver(Observer)}.
     40  *
     41  * <p> An observer added with a Lifecycle will be automatically removed if the corresponding
     42  * Lifecycle moves to {@link Lifecycle.State#DESTROYED} state. This is especially useful for
     43  * activities and fragments where they can safely observe LiveData and not worry about leaks:
     44  * they will be instantly unsubscribed when they are destroyed.
     45  *
     46  * <p>
     47  * In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods
     48  * to get notified when number of active {@link Observer}s change between 0 and 1.
     49  * This allows LiveData to release any heavy resources when it does not have any Observers that
     50  * are actively observing.
     51  * <p>
     52  * This class is designed to hold individual data fields of {@link ViewModel},
     53  * but can also be used for sharing data between different modules in your application
     54  * in a decoupled fashion.
     55  *
     56  * @param <T> The type of data held by this instance
     57  * @see ViewModel
     58  */
     59 public abstract class LiveData<T> {
     60     private final Object mDataLock = new Object();
     61     static final int START_VERSION = -1;
     62     private static final Object NOT_SET = new Object();
     63 
     64     private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
     65             new SafeIterableMap<>();
     66 
     67     // how many observers are in active state
     68     private int mActiveCount = 0;
     69     private volatile Object mData = NOT_SET;
     70     // when setData is called, we set the pending data and actual data swap happens on the main
     71     // thread
     72     private volatile Object mPendingData = NOT_SET;
     73     private int mVersion = START_VERSION;
     74 
     75     private boolean mDispatchingValue;
     76     @SuppressWarnings("FieldCanBeLocal")
     77     private boolean mDispatchInvalidated;
     78     private final Runnable mPostValueRunnable = new Runnable() {
     79         @Override
     80         public void run() {
     81             Object newValue;
     82             synchronized (mDataLock) {
     83                 newValue = mPendingData;
     84                 mPendingData = NOT_SET;
     85             }
     86             //noinspection unchecked
     87             setValue((T) newValue);
     88         }
     89     };
     90 
     91     private void considerNotify(ObserverWrapper observer) {
     92         if (!observer.mActive) {
     93             return;
     94         }
     95         // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
     96         //
     97         // we still first check observer.active to keep it as the entrance for events. So even if
     98         // the observer moved to an active state, if we've not received that event, we better not
     99         // notify for a more predictable notification order.
    100         if (!observer.shouldBeActive()) {
    101             observer.activeStateChanged(false);
    102             return;
    103         }
    104         if (observer.mLastVersion >= mVersion) {
    105             return;
    106         }
    107         observer.mLastVersion = mVersion;
    108         //noinspection unchecked
    109         observer.mObserver.onChanged((T) mData);
    110     }
    111 
    112     private void dispatchingValue(@Nullable ObserverWrapper initiator) {
    113         if (mDispatchingValue) {
    114             mDispatchInvalidated = true;
    115             return;
    116         }
    117         mDispatchingValue = true;
    118         do {
    119             mDispatchInvalidated = false;
    120             if (initiator != null) {
    121                 considerNotify(initiator);
    122                 initiator = null;
    123             } else {
    124                 for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
    125                         mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
    126                     considerNotify(iterator.next().getValue());
    127                     if (mDispatchInvalidated) {
    128                         break;
    129                     }
    130                 }
    131             }
    132         } while (mDispatchInvalidated);
    133         mDispatchingValue = false;
    134     }
    135 
    136     /**
    137      * Adds the given observer to the observers list within the lifespan of the given
    138      * owner. The events are dispatched on the main thread. If LiveData already has data
    139      * set, it will be delivered to the observer.
    140      * <p>
    141      * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
    142      * or {@link Lifecycle.State#RESUMED} state (active).
    143      * <p>
    144      * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
    145      * automatically be removed.
    146      * <p>
    147      * When data changes while the {@code owner} is not active, it will not receive any updates.
    148      * If it becomes active again, it will receive the last available data automatically.
    149      * <p>
    150      * LiveData keeps a strong reference to the observer and the owner as long as the
    151      * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
    152      * the observer &amp; the owner.
    153      * <p>
    154      * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
    155      * ignores the call.
    156      * <p>
    157      * If the given owner, observer tuple is already in the list, the call is ignored.
    158      * If the observer is already in the list with another owner, LiveData throws an
    159      * {@link IllegalArgumentException}.
    160      *
    161      * @param owner    The LifecycleOwner which controls the observer
    162      * @param observer The observer that will receive the events
    163      */
    164     @MainThread
    165     public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    166         assertMainThread("observe");
    167         if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    168             // ignore
    169             return;
    170         }
    171         LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    172         ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    173         if (existing != null && !existing.isAttachedTo(owner)) {
    174             throw new IllegalArgumentException("Cannot add the same observer"
    175                     + " with different lifecycles");
    176         }
    177         if (existing != null) {
    178             return;
    179         }
    180         owner.getLifecycle().addObserver(wrapper);
    181     }
    182 
    183     /**
    184      * Adds the given observer to the observers list. This call is similar to
    185      * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which
    186      * is always active. This means that the given observer will receive all events and will never
    187      * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop
    188      * observing this LiveData.
    189      * While LiveData has one of such observers, it will be considered
    190      * as active.
    191      * <p>
    192      * If the observer was already added with an owner to this LiveData, LiveData throws an
    193      * {@link IllegalArgumentException}.
    194      *
    195      * @param observer The observer that will receive the events
    196      */
    197     @MainThread
    198     public void observeForever(@NonNull Observer<? super T> observer) {
    199         assertMainThread("observeForever");
    200         AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    201         ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    202         if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
    203             throw new IllegalArgumentException("Cannot add the same observer"
    204                     + " with different lifecycles");
    205         }
    206         if (existing != null) {
    207             return;
    208         }
    209         wrapper.activeStateChanged(true);
    210     }
    211 
    212     /**
    213      * Removes the given observer from the observers list.
    214      *
    215      * @param observer The Observer to receive events.
    216      */
    217     @MainThread
    218     public void removeObserver(@NonNull final Observer<? super T> observer) {
    219         assertMainThread("removeObserver");
    220         ObserverWrapper removed = mObservers.remove(observer);
    221         if (removed == null) {
    222             return;
    223         }
    224         removed.detachObserver();
    225         removed.activeStateChanged(false);
    226     }
    227 
    228     /**
    229      * Removes all observers that are tied to the given {@link LifecycleOwner}.
    230      *
    231      * @param owner The {@code LifecycleOwner} scope for the observers to be removed.
    232      */
    233     @SuppressWarnings("WeakerAccess")
    234     @MainThread
    235     public void removeObservers(@NonNull final LifecycleOwner owner) {
    236         assertMainThread("removeObservers");
    237         for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
    238             if (entry.getValue().isAttachedTo(owner)) {
    239                 removeObserver(entry.getKey());
    240             }
    241         }
    242     }
    243 
    244     /**
    245      * Posts a task to a main thread to set the given value. So if you have a following code
    246      * executed in the main thread:
    247      * <pre class="prettyprint">
    248      * liveData.postValue("a");
    249      * liveData.setValue("b");
    250      * </pre>
    251      * The value "b" would be set at first and later the main thread would override it with
    252      * the value "a".
    253      * <p>
    254      * If you called this method multiple times before a main thread executed a posted task, only
    255      * the last value would be dispatched.
    256      *
    257      * @param value The new value
    258      */
    259     protected void postValue(T value) {
    260         boolean postTask;
    261         synchronized (mDataLock) {
    262             postTask = mPendingData == NOT_SET;
    263             mPendingData = value;
    264         }
    265         if (!postTask) {
    266             return;
    267         }
    268         ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    269     }
    270 
    271     /**
    272      * Sets the value. If there are active observers, the value will be dispatched to them.
    273      * <p>
    274      * This method must be called from the main thread. If you need set a value from a background
    275      * thread, you can use {@link #postValue(Object)}
    276      *
    277      * @param value The new value
    278      */
    279     @MainThread
    280     protected void setValue(T value) {
    281         assertMainThread("setValue");
    282         mVersion++;
    283         mData = value;
    284         dispatchingValue(null);
    285     }
    286 
    287     /**
    288      * Returns the current value.
    289      * Note that calling this method on a background thread does not guarantee that the latest
    290      * value set will be received.
    291      *
    292      * @return the current value
    293      */
    294     @Nullable
    295     public T getValue() {
    296         Object data = mData;
    297         if (data != NOT_SET) {
    298             //noinspection unchecked
    299             return (T) data;
    300         }
    301         return null;
    302     }
    303 
    304     int getVersion() {
    305         return mVersion;
    306     }
    307 
    308     /**
    309      * Called when the number of active observers change to 1 from 0.
    310      * <p>
    311      * This callback can be used to know that this LiveData is being used thus should be kept
    312      * up to date.
    313      */
    314     protected void onActive() {
    315 
    316     }
    317 
    318     /**
    319      * Called when the number of active observers change from 1 to 0.
    320      * <p>
    321      * This does not mean that there are no observers left, there may still be observers but their
    322      * lifecycle states aren't {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}
    323      * (like an Activity in the back stack).
    324      * <p>
    325      * You can check if there are observers via {@link #hasObservers()}.
    326      */
    327     protected void onInactive() {
    328 
    329     }
    330 
    331     /**
    332      * Returns true if this LiveData has observers.
    333      *
    334      * @return true if this LiveData has observers
    335      */
    336     @SuppressWarnings("WeakerAccess")
    337     public boolean hasObservers() {
    338         return mObservers.size() > 0;
    339     }
    340 
    341     /**
    342      * Returns true if this LiveData has active observers.
    343      *
    344      * @return true if this LiveData has active observers
    345      */
    346     @SuppressWarnings("WeakerAccess")
    347     public boolean hasActiveObservers() {
    348         return mActiveCount > 0;
    349     }
    350 
    351     class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    352         @NonNull final LifecycleOwner mOwner;
    353 
    354         LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
    355             super(observer);
    356             mOwner = owner;
    357         }
    358 
    359         @Override
    360         boolean shouldBeActive() {
    361             return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    362         }
    363 
    364         @Override
    365         public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    366             if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    367                 removeObserver(mObserver);
    368                 return;
    369             }
    370             activeStateChanged(shouldBeActive());
    371         }
    372 
    373         @Override
    374         boolean isAttachedTo(LifecycleOwner owner) {
    375             return mOwner == owner;
    376         }
    377 
    378         @Override
    379         void detachObserver() {
    380             mOwner.getLifecycle().removeObserver(this);
    381         }
    382     }
    383 
    384     private abstract class ObserverWrapper {
    385         final Observer<? super T> mObserver;
    386         boolean mActive;
    387         int mLastVersion = START_VERSION;
    388 
    389         ObserverWrapper(Observer<? super T> observer) {
    390             mObserver = observer;
    391         }
    392 
    393         abstract boolean shouldBeActive();
    394 
    395         boolean isAttachedTo(LifecycleOwner owner) {
    396             return false;
    397         }
    398 
    399         void detachObserver() {
    400         }
    401 
    402         void activeStateChanged(boolean newActive) {
    403             if (newActive == mActive) {
    404                 return;
    405             }
    406             // immediately set active state, so we'd never dispatch anything to inactive
    407             // owner
    408             mActive = newActive;
    409             boolean wasInactive = LiveData.this.mActiveCount == 0;
    410             LiveData.this.mActiveCount += mActive ? 1 : -1;
    411             if (wasInactive && mActive) {
    412                 onActive();
    413             }
    414             if (LiveData.this.mActiveCount == 0 && !mActive) {
    415                 onInactive();
    416             }
    417             if (mActive) {
    418                 dispatchingValue(this);
    419             }
    420         }
    421     }
    422 
    423     private class AlwaysActiveObserver extends ObserverWrapper {
    424 
    425         AlwaysActiveObserver(Observer<? super T> observer) {
    426             super(observer);
    427         }
    428 
    429         @Override
    430         boolean shouldBeActive() {
    431             return true;
    432         }
    433     }
    434 
    435     private static void assertMainThread(String methodName) {
    436         if (!ArchTaskExecutor.getInstance().isMainThread()) {
    437             throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
    438                     + " thread");
    439         }
    440     }
    441 }
    442