LiveData.java revision 459caadc8f6875fc78a36ae716193bf991f0808c
1c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar/*
2c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * Copyright (C) 2016 The Android Open Source Project
3c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
4c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * you may not use this file except in compliance with the License.
6c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * You may obtain a copy of the License at
7c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
8c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
10c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * Unless required by applicable law or agreed to in writing, software
11c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * See the License for the specific language governing permissions and
14c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * limitations under the License.
15c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */
16c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
17c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarpackage com.android.support.lifecycle;
18c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
19c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport static com.android.support.lifecycle.Lifecycle.DESTROYED;
20c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport static com.android.support.lifecycle.Lifecycle.STARTED;
21c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
22c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport android.support.annotation.MainThread;
23c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport android.support.annotation.Nullable;
24c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
25c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinetsimport com.android.support.apptoolkit.internal.SafeIterableMap;
2634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport com.android.support.executors.AppToolkitTaskExecutor;
2734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
28c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinetsimport java.util.Iterator;
29c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinetsimport java.util.Map;
30c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
31c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar/**
32e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * LiveData is a data holder class that can be observed within a given lifecycle.
33e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * This means that an {@link Observer} can be added in a pair with a {@link LifecycleProvider}, and
34e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * this observer will be notified about modifications of the wrapped data only if the paired
35e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * LifecycleProvider is in active state. LifecycleProvider is considered as active, if its state is
36e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * {@link Lifecycle#STARTED} or {@link Lifecycle#RESUMED}. An observer added without a
3789b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * LifecycleProvider is considered as always active and thus will be always notified about
3889b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * modifications. For those observers, you should manually call {@link #removeObserver(Observer)}.
39e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
40e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p> An observer added with a Lifecycle will be automatically removed if the corresponding
41e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * Lifecycle moves to {@link Lifecycle#DESTROYED} state. This is especially useful for activities
4289b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * and fragments where they can safely observe LiveData and not worry about leaks: they will be
4389b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * instantly unsubscribed when they are destroyed.
44e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
45e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p>
46e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods
4789b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * to get notified when number of active {@link Observer}s change between 0 and 1.
4889b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * This allows LiveData to release any heavy resources when it does not have any Observers that
4989b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * are actively observing.
50c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p>
51e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * This class is designed to hold individual data fields of {@link ViewModel},
52e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * but can also be used for sharing data between different modules in your application
53e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * in a decoupled fashion.
54c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
55c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * @param <T> The type of data hold by this instance
56e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see ViewModel
57c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */
58c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar@SuppressWarnings({"WeakerAccess", "unused"})
59c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets// TODO: Thread checks are too strict right now, we may consider automatically moving them to main
6034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar// thread.
61c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarpublic class LiveData<T> {
6234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private final Object mDataLock = new Object();
63c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private static final int START_VERSION = -1;
64c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private static final Object NOT_SET = new Object();
65c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
667c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    private static final LifecycleProvider ALWAYS_ON = new LifecycleProvider() {
677c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
687c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        private LifecycleRegistry mRegistry = init();
697c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
707c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        private LifecycleRegistry init() {
717c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            LifecycleRegistry registry = new LifecycleRegistry(this);
727c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.ON_CREATE);
737c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.ON_START);
747c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.ON_RESUME);
757c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            return registry;
767c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        }
777c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
787c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        @Override
797c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        public Lifecycle getLifecycle() {
807c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            return mRegistry;
817c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        }
827c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    };
837c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
84c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private SafeIterableMap<Observer<T>, LifecycleBoundObserver> mObservers =
85c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            new SafeIterableMap<>();
86c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
87c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    // how many observers are in active state
88c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mActiveCount = 0;
89c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private Object mData = NOT_SET;
9034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // when setData is called, we set the pending data and actual data swap happens on the main
9134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // thread
9234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private volatile Object mPendingData = NOT_SET;
93c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mVersion = START_VERSION;
94c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
95c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private boolean mDispatchingValue;
96c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    @SuppressWarnings("FieldCanBeLocal")
97c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private boolean mDispatchInvalidated;
98459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    private final Runnable mPostValueRunnable = new Runnable() {
99459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        @Override
100459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        public void run() {
101459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            Object newValue;
102459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            synchronized (mDataLock) {
103459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets                newValue = mPendingData;
104459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets                mPendingData = NOT_SET;
105459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            }
106459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            //noinspection unchecked
107459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            setValue((T) newValue);
108459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        }
109459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    };
110c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
111c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private void considerNotify(LifecycleBoundObserver observer) {
112c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (!observer.active) {
113c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
114c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
115c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (observer.lastVersion >= mVersion) {
116c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
117c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
118c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        observer.lastVersion = mVersion;
119c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        //noinspection unchecked
120c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        observer.observer.onChanged((T) mData);
121c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    }
122c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
123c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
124c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (mDispatchingValue) {
125c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            mDispatchInvalidated = true;
126c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
127c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
128c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        mDispatchingValue = true;
129c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        do {
130c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            mDispatchInvalidated = false;
131c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (initiator != null) {
132c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                considerNotify(initiator);
133c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                initiator = null;
134c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            } else {
135c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                for (Iterator<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =
136c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
137c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    considerNotify(iterator.next().getValue());
138c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    if (mDispatchInvalidated) {
139c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                        break;
1404d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    }
1414d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                }
142c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
143c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        } while (mDispatchInvalidated);
144c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        mDispatchingValue = false;
145c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    }
146c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
147c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
148c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Adds the given observer to the observers list within the lifespan of the given provider. The
149c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets     * events are dispatched on the main thread. If LiveData already has data set, it will be
150c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets     * delivered to the observer.
151c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
152c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * The observer will only receive events if the provider is in {@link Lifecycle#STARTED} or
153c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * {@link Lifecycle#RESUMED} state (active).
154c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
155c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the provider moves to the {@link Lifecycle#DESTROYED} state, the observer will
156c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * automatically be removed.
157c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
158c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * When data changes while the {@code provider} is not active, it will not receive any updates.
159c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If it becomes active again, it will receive the last available data automatically.
160c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
161c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * LiveData keeps a strong reference to the observer and the provider as long as the given
162c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * LifecycleProvider is not destroyed. When it is destroyed, LiveData removes references to
163c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * the observer & the provider.
164c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
165c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the given provider is already in {@link Lifecycle#DESTROYED} state, LiveData ignores the
166c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * call.
167c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
168c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the given provider, observer tuple is already in the list, the call is ignored.
169c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the observer is already in the list with another provider, LiveData throws an
170c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * {@link IllegalArgumentException}.
171c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
172c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param provider The LifecycleProvider which controls the observer
173c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The observer that will receive the events
174c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
175c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
176c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void observe(LifecycleProvider provider, Observer<T> observer) {
177c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        if (provider.getLifecycle().getCurrentState() == DESTROYED) {
178c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            // ignore
179c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return;
180c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
181c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(provider, observer);
182c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
183c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (existing != null && existing.provider != wrapper.provider) {
184c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            throw new IllegalArgumentException("Cannot add the same observer"
185c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    + " with different lifecycles");
186c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
187c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (existing != null) {
188c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
189c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
190c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        provider.getLifecycle().addObserver(wrapper);
191c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        wrapper.activeStateChanged(isActiveState(provider.getLifecycle().getCurrentState()));
192c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
193c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
194c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
1957c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * Adds the given observer to the observers list. This call is similar to
1967c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * {@link LiveData#observe(LifecycleProvider, Observer)} with a LifecycleProvider, which
1977c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * is always active. This means that the given observer will receive all events and will never
1987c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop
1997c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * observing this LiveData.
2007c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * While LiveData has one of such observers, it will be considered
2017c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * as active.
2027c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * <p>
2037c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * If the observer was already added with a provider to this LiveData, LiveData throws an
2047c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * {@link IllegalArgumentException}.
205c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets     *
2067c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * @param observer The observer that will receive the events
2077c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     */
2087c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    @MainThread
2097c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    public void observe(Observer<T> observer) {
2107c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        observe(ALWAYS_ON, observer);
2117c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    }
2127c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
2137c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    /**
214c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Removes the given observer from the observers list.
215c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
216c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The Observer to receive events.
217c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
218c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
219c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void removeObserver(final Observer<T> observer) {
22034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObserver");
221c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        LifecycleBoundObserver removed = mObservers.remove(observer);
222c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (removed == null) {
223c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
224c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
225c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        removed.provider.getLifecycle().removeObserver(removed);
226c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        removed.activeStateChanged(false);
227c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
228c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
229c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
230c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Removes all observers that are tied to the given LifecycleProvider.
231c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
232c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param provider The provider scope for the observers to be removed.
233c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
234c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
235c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void removeObservers(final LifecycleProvider provider) {
23634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObservers");
237c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        for (Map.Entry<Observer<T>, LifecycleBoundObserver> entry : mObservers) {
238c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (entry.getValue().provider == provider) {
239c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                removeObserver(entry.getKey());
240c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
241c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
242c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
243c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
244c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
245459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * Posts a task to a main thread to set the given value. So if you have a following code
246459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * executed in the main thread:
247459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * <pre class="prettyprint">
248459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * liveData.postValue("a");
249459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * liveData.setValue("b");
250459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * </pre>
251459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * The value "b" would be set at first and later the main thread would override it with
252459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * the value "a".
25334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
254459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * If you called this method multiple times before a main thread executed a posted task, only
255459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * the last value would be dispatched.
256c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
257c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param value The new value
258c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
259459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    public void postValue(T value) {
260459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        boolean postTask;
26134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        synchronized (mDataLock) {
262459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            postTask = mPendingData == NOT_SET;
26334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            mPendingData = value;
26434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
265459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        if (!postTask) {
266459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            return;
267459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        }
268459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
269459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    }
270459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets
271459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    /**
272459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * Sets the value. If there are active observers, the value will be dispatched to them.
273459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * <p>
274459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * This method must be called from the main thread. If you need set a value from a background
275459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * thread, you can use {@link #postValue(Object)}
276459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     *
277459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * @param value The new value
278459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     */
279459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    @MainThread
280459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    public void setValue(T value) {
281459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        assertMainThread("setValue");
282459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        mVersion++;
283459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        mData = value;
284459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        dispatchingValue(null);
285c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
286c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
287c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
288c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Returns the current value.
289c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Note that calling this method on a background thread does not guarantee that the latest
290c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * value set will be received.
291c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
292c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @return the current value
293c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
294c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @Nullable
295c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public T getValue() {
29634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // we do not return pending data here to be able to serve a consistent view to the main
29734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // thread.
298c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        Object data = mData;
299c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        if (mData != NOT_SET) {
300c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            //noinspection unchecked
301c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return (T) mData;
302c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
303c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        return null;
304c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
305c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
306c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3074d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change to 1 from 0.
308c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3094d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This callback can be used to know that this LiveData is being used thus should be kept
3104d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * up to date.
311c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
3124d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onActive() {
3134d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
314c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
315c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
316c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3174d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change from 1 to 0.
318c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3194d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This does not mean that there are no observers left, there may still be observers but their
3204d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * lifecycle states is not {@link Lifecycle#STARTED} or {@link Lifecycle#STOPPED} (like an
3214d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Activity in the back stack).
3224d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * <p>
3234d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * You can get the number of observers via {@link #getObserverCount()}.
3244d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
3254d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onInactive() {
3264d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3274d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
3284d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3294d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
3304d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Returns the number of observers.
33134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
33234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * If called on a background thread, the value might be unreliable.
333c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
3344d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * @return The number of observers
335c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
3364d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    public int getObserverCount() {
337c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        return mObservers.size();
338c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
339c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
3404d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
3414d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Returns the number of active observers.
34234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
34334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * If called on a background thread, the value might be unreliable.
3444d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     *
3454d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * @return The number of active observers
3464d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
3474d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    public int getActiveObserverCount() {
3484d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        return mActiveCount;
3494d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
350c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
351c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    class LifecycleBoundObserver implements LifecycleObserver {
352c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public final LifecycleProvider provider;
353c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public final Observer<T> observer;
354c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public boolean active;
355c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public int lastVersion = START_VERSION;
356c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
357c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        LifecycleBoundObserver(LifecycleProvider provider, Observer<T> observer) {
358c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            this.provider = provider;
359c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            this.observer = observer;
360c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
361c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
362c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        @SuppressWarnings("unused")
363c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        @OnLifecycleEvent(Lifecycle.ANY)
364c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        void onStateChange() {
365c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            if (provider.getLifecycle().getCurrentState() == DESTROYED) {
366c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                removeObserver(observer);
367c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                return;
368c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
369c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            // immediately set active state, so we'd never dispatch anything to inactive provider
370c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            activeStateChanged(isActiveState(provider.getLifecycle().getCurrentState()));
371c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
372c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
373c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
374c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        void activeStateChanged(boolean newActive) {
375c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (newActive == active) {
376c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                return;
377c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
378c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            active = newActive;
379c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            boolean inInActive = mActiveCount == 0;
380c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            mActiveCount += active ? 1 : -1;
381c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (inInActive && active) {
382c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                onActive();
383c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
384c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (!inInActive && !active) {
385c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                onInactive();
386c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
387c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (active) {
388c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                dispatchingValue(this);
389c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
390c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
391c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
392c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
393c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    static boolean isActiveState(@Lifecycle.State int state) {
394c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        return state >= STARTED;
395c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
39634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
39734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private void assertMainThread(String methodName) {
39834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        if (!AppToolkitTaskExecutor.getInstance().isMainThread()) {
39934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
40034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " thread. You can easily move the call to main thread using"
40134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " AppToolkitTaskExecutor.");
40234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
40334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
404c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar}
405