LiveData.java revision 89b6198c76e51a505556d7f4e57d3e48e24d5ece
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 Boyarimport android.support.annotation.VisibleForTesting;
25c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
2634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport com.android.support.apptoolkit.internal.ObserverSet;
2734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyarimport com.android.support.executors.AppToolkitTaskExecutor;
2834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
29c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar/**
30e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * LiveData is a data holder class that can be observed within a given lifecycle.
31e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * This means that an {@link Observer} can be added in a pair with a {@link LifecycleProvider}, and
32e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * this observer will be notified about modifications of the wrapped data only if the paired
33e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * LifecycleProvider is in active state. LifecycleProvider is considered as active, if its state is
34e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * {@link Lifecycle#STARTED} or {@link Lifecycle#RESUMED}. An observer added without a
3589b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * LifecycleProvider is considered as always active and thus will be always notified about
3689b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * modifications. For those observers, you should manually call {@link #removeObserver(Observer)}.
37e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
38e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p> An observer added with a Lifecycle will be automatically removed if the corresponding
39e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * Lifecycle moves to {@link Lifecycle#DESTROYED} state. This is especially useful for activities
4089b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * and fragments where they can safely observe LiveData and not worry about leaks: they will be
4189b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * instantly unsubscribed when they are destroyed.
42e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets *
43e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p>
44e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods
4589b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * to get notified when number of active {@link Observer}s change between 0 and 1.
4689b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * This allows LiveData to release any heavy resources when it does not have any Observers that
4789b6198c76e51a505556d7f4e57d3e48e24d5eceYigit Boyar * are actively observing.
48c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p>
49e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * This class is designed to hold individual data fields of {@link ViewModel},
50e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * but can also be used for sharing data between different modules in your application
51e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * in a decoupled fashion.
52c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar *
53c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * @param <T> The type of data hold by this instance
54e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see ViewModel
55c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */
56c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar@SuppressWarnings({"WeakerAccess", "unused"})
574d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar// TODO the usage of ObserverSet needs to be cleaned. Maybe we should simplify the rules.
5834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar// Thread checks are too strict right now, we may consider automatically moving them to main
5934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar// thread.
60c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyarpublic class LiveData<T> {
6134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private final Object mDataLock = new Object();
62c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private static final int START_VERSION = -1;
63c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private static final Object NOT_SET = new Object();
644d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    private boolean mPendingActiveChanges = false;
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
84c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @VisibleForTesting
85c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    ObserverSet<LifecycleBoundObserver> mObservers =
86c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            new ObserverSet<LifecycleBoundObserver>() {
87c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                @Override
88c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                protected boolean checkEquality(LifecycleBoundObserver existing,
89c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        LifecycleBoundObserver added) {
90c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    if (existing.observer == added.observer) {
91c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        if (existing.provider != added.provider) {
92c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                            throw new IllegalArgumentException("Cannot add the same observer twice"
93c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                                    + " to the LiveData");
94c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        }
95c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        return true;
96c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    }
97c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    return false;
98c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
99c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
100c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                @Override
101c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                protected void onAdded(LifecycleBoundObserver observer) {
102c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    observer.onAdded();
103c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    mObserverCount++;
104c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    if (observer.active) {
105c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        mActiveCount++;
106c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        if (mActiveCount == 1) {
1074d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            onActive();
108c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        }
109c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    }
110c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    if (mData != NOT_SET) {
111c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        //noinspection unchecked
112c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        observer.considerNotify((T) mData, mVersion);
113c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    }
114c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
115c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
116c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                @Override
117c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                protected void onRemoved(LifecycleBoundObserver observer) {
118c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    if (observer.active) {
119c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        mActiveCount--;
120c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        if (mActiveCount == 0) {
1214d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            onInactive();
122c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                        }
123c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    }
124c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    mObserverCount--;
125c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    observer.onRemoved();
126c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
1274d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
1284d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                @Override
1294d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                protected void onSync() {
1304d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    if (!mPendingActiveChanges) {
1314d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        return;
1324d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    }
1334d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    forEach(mUpdateActiveCount);
1344d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    mPendingActiveChanges = false;
1354d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                }
136c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            };
137c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
138c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    // how many observers are in active state
139c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mActiveCount = 0;
140c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    // how many observers do we have
141c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mObserverCount = 0;
142c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
143c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private Object mData = NOT_SET;
14434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // when setData is called, we set the pending data and actual data swap happens on the main
14534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    // thread
14634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private volatile Object mPendingData = NOT_SET;
147c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private int mVersion = START_VERSION;
148c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
149c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private ObserverSet.Callback<LifecycleBoundObserver> mDispatchCallback =
150c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            new ObserverSet.Callback<LifecycleBoundObserver>() {
151c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                @Override
152c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                public void run(LifecycleBoundObserver observer) {
153c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    //noinspection unchecked
154c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    observer.considerNotify((T) mData, mVersion);
155c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
156c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            };
157c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
1584d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    private ObserverSet.Callback<LifecycleBoundObserver> mUpdateActiveCount =
1594d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            new ObserverSet.Callback<LifecycleBoundObserver>() {
1604d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                @Override
1614d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                public void run(LifecycleBoundObserver observer) {
1624d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    if (observer.pendingActiveStateChange == null) {
1634d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        return;
1644d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    }
1654d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    boolean newValue = observer.pendingActiveStateChange;
1664d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    observer.pendingActiveStateChange = null;
1674d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    observer.active = newValue;
1684d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    if (newValue) {
1694d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        mActiveCount++;
1704d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        if (mActiveCount == 1) {
1714d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            onActive();
1724d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        }
1734d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        if (mData != NOT_SET) {
1744d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            //noinspection unchecked
1754d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            observer.considerNotify((T) mData, mVersion);
1764d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        }
1774d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    } else {
1784d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        mActiveCount--;
1794d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        if (mActiveCount == 0) {
1804d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                            onInactive();
1814d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                        }
1824d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    }
1834d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                }
1844d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            };
185c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
186c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Adds the given observer to the observers list within the lifespan of the given provider. The
187c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * events are dispatched on the main thread. If LiveData already has data set, it is instantly
188c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * delivered to the observer before this call returns.
189c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
190c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * The observer will only receive events if the provider is in {@link Lifecycle#STARTED} or
191c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * {@link Lifecycle#RESUMED} state (active).
192c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
193c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the provider moves to the {@link Lifecycle#DESTROYED} state, the observer will
194c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * automatically be removed.
195c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
196c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * When data changes while the {@code provider} is not active, it will not receive any updates.
197c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If it becomes active again, it will receive the last available data automatically.
198c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
199c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * LiveData keeps a strong reference to the observer and the provider as long as the given
200c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * LifecycleProvider is not destroyed. When it is destroyed, LiveData removes references to
201c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * the observer & the provider.
202c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
203c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the given provider is already in {@link Lifecycle#DESTROYED} state, LiveData ignores the
204c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * call.
205c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
206c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the given provider, observer tuple is already in the list, the call is ignored.
207c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * If the observer is already in the list with another provider, LiveData throws an
208c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * {@link IllegalArgumentException}.
209c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
210c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param provider The LifecycleProvider which controls the observer
211c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The observer that will receive the events
212c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
213c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
214c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void observe(LifecycleProvider provider, Observer<T> observer) {
21534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("observe");
216c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        if (provider.getLifecycle().getCurrentState() == DESTROYED) {
217c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            // ignore
218c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return;
219c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
220c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        final LifecycleBoundObserver wrapper = new LifecycleBoundObserver(provider, observer);
221c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        mObservers.add(wrapper);
222c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
223c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
224c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
2257c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * Adds the given observer to the observers list. This call is similar to
2267c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * {@link LiveData#observe(LifecycleProvider, Observer)} with a LifecycleProvider, which
2277c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * is always active. This means that the given observer will receive all events and will never
2287c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop
2297c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * observing this LiveData.
2307c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * While LiveData has one of such observers, it will be considered
2317c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * as active.
2327c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * <p>
2337c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * If the observer was already added with a provider to this LiveData, LiveData throws an
2347c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * {@link IllegalArgumentException}.
2357c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
2367c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     * @param observer The observer that will receive the events
2377c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets     */
2387c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    @MainThread
2397c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    public void observe(Observer<T> observer) {
2407c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets        observe(ALWAYS_ON, observer);
2417c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    }
2427c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets
2437c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets    /**
244c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Removes the given observer from the observers list.
245c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
246c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param observer The Observer to receive events.
247c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
248c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
249c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void removeObserver(final Observer<T> observer) {
25034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObserver");
251c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        // TODO make it efficient
252c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        mObservers.forEach(new ObserverSet.Callback<LifecycleBoundObserver>() {
253c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            @Override
254c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            public void run(LifecycleBoundObserver key) {
255c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                if (key.observer == observer) {
256c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    mObservers.remove(key);
257c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
258c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
259c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        });
260c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
261c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
262c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
263c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Removes all observers that are tied to the given LifecycleProvider.
264c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
265c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param provider The provider scope for the observers to be removed.
266c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
267c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @MainThread
268c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public void removeObservers(final LifecycleProvider provider) {
26934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        assertMainThread("removeObservers");
270c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        // TODO make it efficient
271c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        mObservers.forEach(new ObserverSet.Callback<LifecycleBoundObserver>() {
272c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            @Override
273c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            public void run(LifecycleBoundObserver key) {
274c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                if (key.provider == provider) {
275c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                    mObservers.remove(key);
276c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                }
277c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
278c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        });
279c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
280c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
281c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
282c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Sets the value. If there are active observers, the value will be dispatched to them.
28334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
28434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * If this method is called on a background thread, the call will be forwarded to the main
28534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * thread so calling {@link #getValue()} right after calling {@code setValue} may
28634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * not return the value that was set.
287c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
288c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @param value The new value
289c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
29034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    public void setValue(final T value) {
29134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // we keep it in pending data so that last set data wins (e.g. we won't be in a case where
29234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // data is set on the main thread at a later time is overridden by data that was set on a
29334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // background thread.
29434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        synchronized (mDataLock) {
29534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            mPendingData = value;
29634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
29734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        AppToolkitTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
29834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            @Override
29934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            public void run() {
30034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                synchronized (mDataLock) {
30134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    if (mPendingData != NOT_SET) {
30234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                        mVersion++;
30334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                        mData = mPendingData;
30434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                        mPendingData = NOT_SET;
30534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    }
30634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                }
30734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                mObservers.forEach(mDispatchCallback);
30834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            }
30934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        });
310c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
311c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
312c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
313c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Returns the current value.
314c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * Note that calling this method on a background thread does not guarantee that the latest
315c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * value set will be received.
316c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
317c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * @return the current value
318c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
319c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @Nullable
320c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    public T getValue() {
32134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // we do not return pending data here to be able to serve a consistent view to the main
32234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        // thread.
323c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        Object data = mData;
324c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        if (mData != NOT_SET) {
325c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            //noinspection unchecked
326c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            return (T) mData;
327c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
328c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        return null;
329c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
330c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
331c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3324d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change to 1 from 0.
333c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3344d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This callback can be used to know that this LiveData is being used thus should be kept
3354d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * up to date.
336c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
3374d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onActive() {
3384d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
339c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
340c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
341c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    /**
3424d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Called when the number of active observers change from 1 to 0.
343c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     * <p>
3444d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * This does not mean that there are no observers left, there may still be observers but their
3454d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * lifecycle states is not {@link Lifecycle#STARTED} or {@link Lifecycle#STOPPED} (like an
3464d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Activity in the back stack).
3474d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * <p>
3484d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * You can get the number of observers via {@link #getObserverCount()}.
3494d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
3504d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    protected void onInactive() {
3514d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3524d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
3534d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar
3544d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
3554d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Returns the number of observers.
35634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
35734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * If called on a background thread, the value might be unreliable.
358c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     *
3594d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * @return The number of observers
360c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar     */
3614d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    public int getObserverCount() {
3624d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        return mObserverCount;
363c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
364c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
3654d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    /**
3664d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * Returns the number of active observers.
36734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * <p>
36834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar     * If called on a background thread, the value might be unreliable.
3694d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     *
3704d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     * @return The number of active observers
3714d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar     */
3724d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    public int getActiveObserverCount() {
3734d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        return mActiveCount;
3744d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    }
375c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
376c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    class LifecycleBoundObserver implements LifecycleObserver {
377c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public final LifecycleProvider provider;
378c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public final Observer<T> observer;
379c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public boolean active;
3804d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        public Boolean pendingActiveStateChange;
381c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public int lastVersion = START_VERSION;
382c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
383c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        LifecycleBoundObserver(LifecycleProvider provider, Observer<T> observer) {
384c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            this.provider = provider;
385c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            this.observer = observer;
386c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
387c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
388c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        private void onAdded() {
389c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            active = isActiveState(provider.getLifecycle().getCurrentState());
390c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            provider.getLifecycle().addObserver(this);
391c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
392c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
393c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        public void onRemoved() {
394c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            provider.getLifecycle().removeObserver(this);
395c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
396c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
397c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        void considerNotify(T data, int version) {
398c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            if (!active) {
399c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                return;
400c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
401c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            if (lastVersion >= version) {
402c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                return;
403c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
404c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            lastVersion = version;
405c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            observer.onChanged(data);
406c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
407c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
408c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        @SuppressWarnings("unused")
409c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        @OnLifecycleEvent(Lifecycle.ANY)
410c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        void onStateChange() {
411c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            if (provider.getLifecycle().getCurrentState() == DESTROYED) {
412c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                removeInternal(this);
413c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar                return;
414c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
415c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            boolean activeNow = isActiveState(provider.getLifecycle().getCurrentState());
4164d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            if (pendingActiveStateChange == null) {
4174d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                if (activeNow != active) {
4184d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    pendingActiveStateChange = activeNow;
4194d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                    onActiveStateChanged(this);
4204d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                }
4214d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            } else if (activeNow != pendingActiveStateChange) {
4224d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar                pendingActiveStateChange = null;
423c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar            }
424c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
425c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
426c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
427c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    private void removeInternal(LifecycleBoundObserver observer) {
428c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        mObservers.remove(observer);
429c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
430c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
431c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    @SuppressWarnings("unchecked")
4324d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar    private void onActiveStateChanged(LifecycleBoundObserver observer) {
4334d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        if (mObservers.isLocked()) {
4344d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            mPendingActiveChanges = true;
4354d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            mObservers.invokeSyncOnUnlock();
4364d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar            return;
437c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        }
4384d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar        mUpdateActiveCount.run(observer);
439c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
440c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar
441c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    static boolean isActiveState(@Lifecycle.State int state) {
442c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar        return state >= STARTED;
443c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar    }
44434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar
44534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    private void assertMainThread(String methodName) {
44634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        if (!AppToolkitTaskExecutor.getInstance().isMainThread()) {
44734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
44834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " thread. You can easily move the call to main thread using"
44934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar                    + " AppToolkitTaskExecutor.");
45034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar        }
45134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar    }
452c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar}
453