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
17package androidx.lifecycle;
18
19import static androidx.lifecycle.Lifecycle.State.DESTROYED;
20import static androidx.lifecycle.Lifecycle.State.STARTED;
21
22import androidx.annotation.MainThread;
23import androidx.annotation.NonNull;
24import androidx.annotation.Nullable;
25import androidx.arch.core.internal.SafeIterableMap;
26import androidx.arch.core.executor.ArchTaskExecutor;
27
28import java.util.Iterator;
29import 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 */
59public 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