LiveData.java revision abf6c87826e1a86fed71d945dc7e7f1aa643ea6c
1c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar/*
264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar * Copyright (C) 2017 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
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.lifecycle;
18c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
1927015a7478beac9e231135207e3e705784cee508Sergey Vasilinetsimport static android.arch.lifecycle.Lifecycle.State.DESTROYED;
2027015a7478beac9e231135207e3e705784cee508Sergey Vasilinetsimport static android.arch.lifecycle.Lifecycle.State.STARTED;
21c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
2264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.core.executor.AppToolkitTaskExecutor;
2364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.core.internal.SafeIterableMap;
2427015a7478beac9e231135207e3e705784cee508Sergey Vasilinetsimport android.arch.lifecycle.Lifecycle.State;
25c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport android.support.annotation.MainThread;
26c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarimport android.support.annotation.Nullable;
27c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit 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.
33e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
34e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * this observer will be notified about modifications of the wrapped data only if the paired
35e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
3627015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}. An observer added via
3727015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * {@link #observeForever(Observer)} is considered as always active and thus will be always notified
3827015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * about modifications. For those observers, you should manually call
3927015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * {@link #removeObserver(Observer)}.
40e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
41e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p> An observer added with a Lifecycle will be automatically removed if the corresponding
4227015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * Lifecycle moves to {@link Lifecycle.State#DESTROYED} state. This is especially useful for
4327015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * activities and fragments where they can safely observe LiveData and not worry about leaks:
4427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * they will be instantly unsubscribed when they are destroyed.
45e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
46e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p>
47e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods
4889b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * to get notified when number of active {@link Observer}s change between 0 and 1.
4989b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * This allows LiveData to release any heavy resources when it does not have any Observers that
5089b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * are actively observing.
51c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p>
52e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * This class is designed to hold individual data fields of {@link ViewModel},
53e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * but can also be used for sharing data between different modules in your application
54e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * in a decoupled fashion.
55c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
56c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * @param <T> The type of data hold by this instance
57e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see ViewModel
58c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */
59c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar@SuppressWarnings({"WeakerAccess", "unused"})
60c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets// TODO: Thread checks are too strict right now, we may consider automatically moving them to main
6134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar// thread.
62abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinetspublic abstract class LiveData<T> {
6334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private final Object mDataLock = new Object();
646ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets    static final int START_VERSION = -1;
65c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private static final Object NOT_SET = new Object();
66c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
67e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets    private static final LifecycleOwner ALWAYS_ON = new LifecycleOwner() {
687c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
697c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        private LifecycleRegistry mRegistry = init();
707c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
717c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        private LifecycleRegistry init() {
727c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            LifecycleRegistry registry = new LifecycleRegistry(this);
73b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
74b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.Event.ON_START);
75b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets            registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
767c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            return registry;
777c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        }
787c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
797c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        @Override
807c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        public Lifecycle getLifecycle() {
817c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets            return mRegistry;
827c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        }
837c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    };
847c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
85c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private SafeIterableMap<Observer<T>, LifecycleBoundObserver> mObservers =
86c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            new SafeIterableMap<>();
87c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
88c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    // how many observers are in active state
89c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mActiveCount = 0;
90c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private Object mData = NOT_SET;
9134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // when setData is called, we set the pending data and actual data swap happens on the main
9234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // thread
9334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private volatile Object mPendingData = NOT_SET;
94c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mVersion = START_VERSION;
95c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
96c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private boolean mDispatchingValue;
97c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    @SuppressWarnings("FieldCanBeLocal")
98c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private boolean mDispatchInvalidated;
99459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    private final Runnable mPostValueRunnable = new Runnable() {
100459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        @Override
101459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        public void run() {
102459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            Object newValue;
103459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            synchronized (mDataLock) {
104459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets                newValue = mPendingData;
105459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets                mPendingData = NOT_SET;
106459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            }
107459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            //noinspection unchecked
108459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            setValue((T) newValue);
109459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        }
110459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    };
111c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
112c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private void considerNotify(LifecycleBoundObserver observer) {
113c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (!observer.active) {
114c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
115c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
1165dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
1175dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        //
1185dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        // we still first check observer.active to keep it as the entrance for events. So even if
1195dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        // the observer moved to an active state, if we've not received that event, we better not
1205dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        // notify for a more predictable notification order.
121e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        if (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
1225dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar            return;
1235dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar        }
124c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (observer.lastVersion >= mVersion) {
125c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
126c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
127c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        observer.lastVersion = mVersion;
128c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        //noinspection unchecked
129c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        observer.observer.onChanged((T) mData);
130c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    }
131c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
132c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
133c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (mDispatchingValue) {
134c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            mDispatchInvalidated = true;
135c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
136c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
137c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        mDispatchingValue = true;
138c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        do {
139c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            mDispatchInvalidated = false;
140c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (initiator != null) {
141c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                considerNotify(initiator);
142c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                initiator = null;
143c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            } else {
144c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                for (Iterator<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =
145c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
146c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    considerNotify(iterator.next().getValue());
147c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    if (mDispatchInvalidated) {
148c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                        break;
1494d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    }
1504d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                }
151c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
152c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        } while (mDispatchInvalidated);
153c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        mDispatchingValue = false;
154c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets    }
155c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets
156c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
157e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * Adds the given observer to the observers list within the lifespan of the given
158e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * owner. The events are dispatched on the main thread. If LiveData already has data
159e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * set, it will be delivered to the observer.
160c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
16127015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
16227015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * or {@link Lifecycle.State#RESUMED} state (active).
163c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
16427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
165c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * automatically be removed.
166c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
167e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * When data changes while the {@code owner} is not active, it will not receive any updates.
168c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If it becomes active again, it will receive the last available data automatically.
169c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
170e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * LiveData keeps a strong reference to the observer and the owner as long as the
171e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
172e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * the observer &amp; the owner.
173c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
17427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
175e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * ignores the call.
176c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
177e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * If the given owner, observer tuple is already in the list, the call is ignored.
178e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * If the observer is already in the list with another owner, LiveData throws an
179c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * {@link IllegalArgumentException}.
180c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
181e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * @param owner    The LifecycleOwner which controls the observer
182c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The observer that will receive the events
183c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
184c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
185e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets    public void observe(LifecycleOwner owner, Observer<T> observer) {
186e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
187c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            // ignore
188c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return;
189c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
190e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
191c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
192e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        if (existing != null && existing.owner != wrapper.owner) {
193c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            throw new IllegalArgumentException("Cannot add the same observer"
194c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                    + " with different lifecycles");
195c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
196c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (existing != null) {
197c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
198c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
199e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        owner.getLifecycle().addObserver(wrapper);
200e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
201c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
202c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
203c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
2047c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * Adds the given observer to the observers list. This call is similar to
205e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which
2067c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * is always active. This means that the given observer will receive all events and will never
2077c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop
2087c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * observing this LiveData.
2097c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * While LiveData has one of such observers, it will be considered
2107c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * as active.
2117c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * <p>
212e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * If the observer was already added with an owner to this LiveData, LiveData throws an
2137c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * {@link IllegalArgumentException}.
214c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets     *
2157c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * @param observer The observer that will receive the events
2167c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     */
2177c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    @MainThread
218d3449ae5a2f97b3654a9e5945a3365acb316891bSergey Vasilinets    public void observeForever(Observer<T> observer) {
2197c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        observe(ALWAYS_ON, observer);
2207c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    }
2217c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
2227c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    /**
223c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Removes the given observer from the observers list.
224c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
225c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The Observer to receive events.
226c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
227c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
228c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void removeObserver(final Observer<T> observer) {
22934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObserver");
230c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        LifecycleBoundObserver removed = mObservers.remove(observer);
231c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        if (removed == null) {
232c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            return;
233c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
234e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        removed.owner.getLifecycle().removeObserver(removed);
235c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        removed.activeStateChanged(false);
236c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
237c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
238c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
239e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * Removes all observers that are tied to the given {@link LifecycleOwner}.
240c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
241e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets     * @param owner The {@code LifecycleOwner} scope for the observers to be removed.
242c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
243c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
244e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets    public void removeObservers(final LifecycleOwner owner) {
24534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObservers");
246c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        for (Map.Entry<Observer<T>, LifecycleBoundObserver> entry : mObservers) {
247e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            if (entry.getValue().owner == owner) {
248c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                removeObserver(entry.getKey());
249c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
250c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
251c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
252c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
253c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
254459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * Posts a task to a main thread to set the given value. So if you have a following code
255459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * executed in the main thread:
256459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * <pre class="prettyprint">
257459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * liveData.postValue("a");
258459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * liveData.setValue("b");
259459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * </pre>
260459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * The value "b" would be set at first and later the main thread would override it with
261459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * the value "a".
26234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
263459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * If you called this method multiple times before a main thread executed a posted task, only
264459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * the last value would be dispatched.
265c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
266c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param value The new value
267c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
2686ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets    protected void postValue(T value) {
269459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        boolean postTask;
27034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        synchronized (mDataLock) {
271459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            postTask = mPendingData == NOT_SET;
27234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            mPendingData = value;
27334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
274459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        if (!postTask) {
275459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets            return;
276459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        }
277459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
278459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    }
279459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets
280459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    /**
281459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * Sets the value. If there are active observers, the value will be dispatched to them.
282459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * <p>
283459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * This method must be called from the main thread. If you need set a value from a background
284459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * thread, you can use {@link #postValue(Object)}
285459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     *
286459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     * @param value The new value
287459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets     */
288459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets    @MainThread
2896ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets    protected void setValue(T value) {
290459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        assertMainThread("setValue");
291459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        mVersion++;
292459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        mData = value;
293459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets        dispatchingValue(null);
294c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
295c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
296c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
297c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Returns the current value.
298c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Note that calling this method on a background thread does not guarantee that the latest
299c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * value set will be received.
300c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
301c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @return the current value
302c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
303c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @Nullable
304c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public T getValue() {
30534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // we do not return pending data here to be able to serve a consistent view to the main
30634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // thread.
307c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        Object data = mData;
308c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        if (mData != NOT_SET) {
309c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            //noinspection unchecked
310c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return (T) mData;
311c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
312c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        return null;
313c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
314c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
3156ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets    int getVersion() {
3166ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets        return mVersion;
3176ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets    }
3186ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets
319c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3204d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change to 1 from 0.
321c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3224d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This callback can be used to know that this LiveData is being used thus should be kept
3234d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * up to date.
324c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
3254d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onActive() {
3264d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
327c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
328c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
329c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3304d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change from 1 to 0.
331c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3324d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This does not mean that there are no observers left, there may still be observers but their
33327015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * lifecycle states aren't {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}
33427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets     * (like an Activity in the back stack).
3354d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * <p>
336abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets     * You can check if there are observers via {@link #hasObservers()}.
3374d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
3384d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onInactive() {
3394d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3404d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
3414d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3424d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
343abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets     * Returns true if this LiveData has observers.
344c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
345abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets     * @return true if this LiveData has observers
346c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
347abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets    public boolean hasObservers() {
348abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets        return mObservers.size() > 0;
349c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
350c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
3514d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
352abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets     * Returns true if this LiveData has active observers.
3534d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     *
354abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets     * @return true if this LiveData has active observers
3554d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
356abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets    public boolean hasActiveObservers() {
357abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets        return mActiveCount > 0;
3584d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
359c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
360c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    class LifecycleBoundObserver implements LifecycleObserver {
361e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        public final LifecycleOwner owner;
362c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public final Observer<T> observer;
363c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public boolean active;
364c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public int lastVersion = START_VERSION;
365c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
366e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets        LifecycleBoundObserver(LifecycleOwner owner, Observer<T> observer) {
367e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            this.owner = owner;
368c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            this.observer = observer;
369c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
370c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
371c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        @SuppressWarnings("unused")
372b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets        @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
373c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        void onStateChange() {
374e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            if (owner.getLifecycle().getCurrentState() == DESTROYED) {
375c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                removeObserver(observer);
376c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                return;
377c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
378e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            // immediately set active state, so we'd never dispatch anything to inactive
379e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            // owner
380e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets            activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
381c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
382c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        }
383c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
384c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets        void activeStateChanged(boolean newActive) {
385c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (newActive == active) {
386c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                return;
387c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
388c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            active = newActive;
3890da9764fa45b24977675265e04e8aff3fc889d04Sergey Vasilinets            boolean wasInactive = LiveData.this.mActiveCount == 0;
3900da9764fa45b24977675265e04e8aff3fc889d04Sergey Vasilinets            LiveData.this.mActiveCount += active ? 1 : -1;
3910da9764fa45b24977675265e04e8aff3fc889d04Sergey Vasilinets            if (wasInactive && active) {
392c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                onActive();
393c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
3940da9764fa45b24977675265e04e8aff3fc889d04Sergey Vasilinets            if (LiveData.this.mActiveCount == 0 && !active) {
395c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                onInactive();
396c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
397c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            if (active) {
398c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets                dispatchingValue(this);
399c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets            }
400c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
401c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
402c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
40327015a7478beac9e231135207e3e705784cee508Sergey Vasilinets    static boolean isActiveState(State state) {
40427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets        return state.isAtLeast(STARTED);
405c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
40634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
40734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private void assertMainThread(String methodName) {
40834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        if (!AppToolkitTaskExecutor.getInstance().isMainThread()) {
40934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
41034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " thread. You can easily move the call to main thread using"
41134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " AppToolkitTaskExecutor.");
41234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
41334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
414c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar}
415