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 17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.lifecycle; 18c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 19ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport static androidx.lifecycle.Lifecycle.State.DESTROYED; 20ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport static androidx.lifecycle.Lifecycle.State.STARTED; 21c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 22ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.MainThread; 23ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.NonNull; 24ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.Nullable; 25ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.arch.core.internal.SafeIterableMap; 26ddee2b5170ae257a7b2494f8aaa8459ebed806dcAurimas Liutikasimport androidx.arch.core.executor.ArchTaskExecutor; 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 * 565cfbb5dc6b92d9901a83628aec597acceb831916shepshapard * @param <T> The type of data held by this instance 57e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see ViewModel 58c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 59abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinetspublic abstract class LiveData<T> { 6034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar private final Object mDataLock = new Object(); 616ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets static final int START_VERSION = -1; 62c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar private static final Object NOT_SET = new Object(); 63c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 648054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = 65c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets new SafeIterableMap<>(); 66c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 67c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar // how many observers are in active state 68c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar private int mActiveCount = 0; 690a44cc5ae154cf23753eca1c020bd6a9b30eeb0dSergey Vasilinets private volatile Object mData = NOT_SET; 7034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar // when setData is called, we set the pending data and actual data swap happens on the main 7134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar // thread 7234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar private volatile Object mPendingData = NOT_SET; 73c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar private int mVersion = START_VERSION; 74c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 75c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets private boolean mDispatchingValue; 76c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets @SuppressWarnings("FieldCanBeLocal") 77c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets private boolean mDispatchInvalidated; 78459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets private final Runnable mPostValueRunnable = new Runnable() { 79459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets @Override 80459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets public void run() { 81459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets Object newValue; 82459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets synchronized (mDataLock) { 83459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets newValue = mPendingData; 84459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets mPendingData = NOT_SET; 85459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets } 86459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets //noinspection unchecked 87459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets setValue((T) newValue); 88459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets } 89459caadc8f6875fc78a36ae716193bf991f0808cSergey Vasilinets }; 90c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets 91406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets private void considerNotify(ObserverWrapper observer) { 92406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (!observer.mActive) { 93c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 94c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 955dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. 965dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar // 975dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar // we still first check observer.active to keep it as the entrance for events. So even if 985dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar // the observer moved to an active state, if we've not received that event, we better not 995dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar // notify for a more predictable notification order. 100406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (!observer.shouldBeActive()) { 1015cfbb5dc6b92d9901a83628aec597acceb831916shepshapard observer.activeStateChanged(false); 1025dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar return; 1035dcab68c2e390acfb016cb889604b85e1257b02fYigit Boyar } 104406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (observer.mLastVersion >= mVersion) { 105c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 106c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 107406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets observer.mLastVersion = mVersion; 108c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets //noinspection unchecked 109406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets observer.mObserver.onChanged((T) mData); 110c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 111c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets 112406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets private void dispatchingValue(@Nullable ObserverWrapper initiator) { 113c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets if (mDispatchingValue) { 114c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets mDispatchInvalidated = true; 115c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 116c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 117c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets mDispatchingValue = true; 118c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets do { 119c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets mDispatchInvalidated = false; 120c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets if (initiator != null) { 121c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets considerNotify(initiator); 122c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets initiator = null; 123c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } else { 1248054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = 125c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { 126c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets considerNotify(iterator.next().getValue()); 127c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets if (mDispatchInvalidated) { 128c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets break; 1294d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar } 1304d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar } 131c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 132c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } while (mDispatchInvalidated); 133c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets mDispatchingValue = false; 134c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 135c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets 136c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar /** 137e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * Adds the given observer to the observers list within the lifespan of the given 138e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * owner. The events are dispatched on the main thread. If LiveData already has data 139e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * set, it will be delivered to the observer. 140c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 14127015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED} 14227015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * or {@link Lifecycle.State#RESUMED} state (active). 143c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 14427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will 145c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * automatically be removed. 146c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 147e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * When data changes while the {@code owner} is not active, it will not receive any updates. 148c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * If it becomes active again, it will receive the last available data automatically. 149c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 150e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * LiveData keeps a strong reference to the observer and the owner as long as the 151e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to 152e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * the observer & the owner. 153c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 15427015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData 155e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * ignores the call. 156c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 157e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * If the given owner, observer tuple is already in the list, the call is ignored. 158e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * If the observer is already in the list with another owner, LiveData throws an 159c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * {@link IllegalArgumentException}. 160c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * 161e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * @param owner The LifecycleOwner which controls the observer 162c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * @param observer The observer that will receive the events 163c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 164c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar @MainThread 1658054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { 1661e6eadb9fb537c6bd81cc6a50ab685711cd84fd9Sergey Vasilinets assertMainThread("observe"); 167e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets if (owner.getLifecycle().getCurrentState() == DESTROYED) { 168c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar // ignore 169c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar return; 170c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 171e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); 172406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); 173406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (existing != null && !existing.isAttachedTo(owner)) { 174c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets throw new IllegalArgumentException("Cannot add the same observer" 175c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets + " with different lifecycles"); 176c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 177c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets if (existing != null) { 178c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 179c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 180e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets owner.getLifecycle().addObserver(wrapper); 181c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 182c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 183c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar /** 1847c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * Adds the given observer to the observers list. This call is similar to 185e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which 1867c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * is always active. This means that the given observer will receive all events and will never 1877c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop 1887c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * observing this LiveData. 1897c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * While LiveData has one of such observers, it will be considered 1907c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * as active. 1917c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * <p> 192e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * If the observer was already added with an owner to this LiveData, LiveData throws an 1937c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * {@link IllegalArgumentException}. 194c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets * 1957c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets * @param observer The observer that will receive the events 1967c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets */ 1977c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets @MainThread 1988054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets public void observeForever(@NonNull Observer<? super T> observer) { 1991e6eadb9fb537c6bd81cc6a50ab685711cd84fd9Sergey Vasilinets assertMainThread("observeForever"); 200406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); 201406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); 202406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) { 203406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets throw new IllegalArgumentException("Cannot add the same observer" 204406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets + " with different lifecycles"); 205406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 206406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (existing != null) { 207406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets return; 208406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 209406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets wrapper.activeStateChanged(true); 2107c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets } 2117c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets 2127c41ee306fc78feaa0043c65bf82e65935bd9d35Sergey Vasilinets /** 213c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * Removes the given observer from the observers list. 214c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * 215c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * @param observer The Observer to receive events. 216c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 217c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar @MainThread 2188054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets public void removeObserver(@NonNull final Observer<? super T> observer) { 21934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar assertMainThread("removeObserver"); 220406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets ObserverWrapper removed = mObservers.remove(observer); 221c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets if (removed == null) { 222c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 223c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 224406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets removed.detachObserver(); 225c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets removed.activeStateChanged(false); 226c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 227c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 228c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar /** 229e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * Removes all observers that are tied to the given {@link LifecycleOwner}. 230c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * 231e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets * @param owner The {@code LifecycleOwner} scope for the observers to be removed. 232c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 233406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @SuppressWarnings("WeakerAccess") 234c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar @MainThread 2359d8d936607b58e83fbf1ef57b5bd9846829abb66Sergey Vasilinets public void removeObservers(@NonNull final LifecycleOwner owner) { 23634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar assertMainThread("removeObservers"); 2378054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) { 238406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (entry.getValue().isAttachedTo(owner)) { 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 */ 2596ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets protected 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 } 268ae36c8b11a64d3cdc9ba6e37d9f3d1d250fdc4a8Yigit Boyar ArchTaskExecutor.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 2806ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets protected 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() { 296c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar Object data = mData; 2970a44cc5ae154cf23753eca1c020bd6a9b30eeb0dSergey Vasilinets if (data != NOT_SET) { 298c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar //noinspection unchecked 2990a44cc5ae154cf23753eca1c020bd6a9b30eeb0dSergey Vasilinets return (T) data; 300c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 301c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar return null; 302c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 303c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 3046ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets int getVersion() { 3056ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets return mVersion; 3066ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets } 3076ca8525782f16bcb4403dc692a1fefd77934aa31Sergey Vasilinets 308c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar /** 3095cf395a3446bc61c8f281464aa88e9cec2c0c177Florina Muntenescu * Called when the number of active observers change to 1 from 0. 310c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 3114d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * This callback can be used to know that this LiveData is being used thus should be kept 3124d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * up to date. 313c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 3144d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar protected void onActive() { 3154d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar 316c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 317c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 318c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar /** 3194d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * Called when the number of active observers change from 1 to 0. 320c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * <p> 3214d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * This does not mean that there are no observers left, there may still be observers but their 32227015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * lifecycle states aren't {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED} 32327015a7478beac9e231135207e3e705784cee508Sergey Vasilinets * (like an Activity in the back stack). 3244d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * <p> 325abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets * You can check if there are observers via {@link #hasObservers()}. 3264d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar */ 3274d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar protected void onInactive() { 3284d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar 3294d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar } 3304d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar 3314d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar /** 332abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets * Returns true if this LiveData has observers. 333c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar * 334abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets * @return true if this LiveData has observers 335c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar */ 336406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @SuppressWarnings("WeakerAccess") 337abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets public boolean hasObservers() { 338abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets return mObservers.size() > 0; 339c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 340c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 3414d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar /** 342abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets * Returns true if this LiveData has active observers. 3434d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar * 344abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets * @return true if this LiveData has active observers 3454d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar */ 346406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @SuppressWarnings("WeakerAccess") 347abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets public boolean hasActiveObservers() { 348abf6c87826e1a86fed71d945dc7e7f1aa643ea6cSergey Vasilinets return mActiveCount > 0; 3494d4bf0391459bec361ec7843447ae60d38c99028Yigit Boyar } 350c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 351406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { 352406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @NonNull final LifecycleOwner mOwner; 353406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 3548054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { 355406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets super(observer); 356406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets mOwner = owner; 357406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 358c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 359406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @Override 360406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets boolean shouldBeActive() { 361406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); 362c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 363c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 364d99995d86cb9d0f97624181e5a553f1a0b8102a1Sergey Vasilinets @Override 365d99995d86cb9d0f97624181e5a553f1a0b8102a1Sergey Vasilinets public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { 366406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { 367406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets removeObserver(mObserver); 368c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar return; 369c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 370406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets activeStateChanged(shouldBeActive()); 371406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 372406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 373406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @Override 374406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets boolean isAttachedTo(LifecycleOwner owner) { 375406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets return mOwner == owner; 376406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 377406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 378406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @Override 379406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets void detachObserver() { 380406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets mOwner.getLifecycle().removeObserver(this); 381406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 382406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 383406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 384406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets private abstract class ObserverWrapper { 3858054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets final Observer<? super T> mObserver; 386406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets boolean mActive; 387406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets int mLastVersion = START_VERSION; 388406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 3898054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets ObserverWrapper(Observer<? super T> observer) { 390406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets mObserver = observer; 391406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 392406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 393406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets abstract boolean shouldBeActive(); 394406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 395406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets boolean isAttachedTo(LifecycleOwner owner) { 396406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets return false; 397406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 398406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 399406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets void detachObserver() { 400c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 401c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 402c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets void activeStateChanged(boolean newActive) { 403406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (newActive == mActive) { 404c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets return; 405c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 406406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets // immediately set active state, so we'd never dispatch anything to inactive 407406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets // owner 408406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets mActive = newActive; 4090da9764fa45b24977675265e04e8aff3fc889d04Sergey Vasilinets boolean wasInactive = LiveData.this.mActiveCount == 0; 410406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets LiveData.this.mActiveCount += mActive ? 1 : -1; 411406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (wasInactive && mActive) { 412c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets onActive(); 413c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 414406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (LiveData.this.mActiveCount == 0 && !mActive) { 415c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets onInactive(); 416c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 417406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets if (mActive) { 418c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets dispatchingValue(this); 419c43ce90b803cdfa033dfc94fa4161371ed6f3ec6Sergey Vasilinets } 420c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 421c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 422c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar 423406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets private class AlwaysActiveObserver extends ObserverWrapper { 424406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 4258054b2b48805260f3efb5afaad0b17b1378d13bdSergey Vasilinets AlwaysActiveObserver(Observer<? super T> observer) { 426406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets super(observer); 427406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 428406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets 429406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets @Override 430406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets boolean shouldBeActive() { 431406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets return true; 432406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets } 433c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar } 43434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar 435406dfb7a30f9fb785412cbe4d4e75503c58dafd9Sergey Vasilinets private static void assertMainThread(String methodName) { 436ae36c8b11a64d3cdc9ba6e37d9f3d1d250fdc4a8Yigit Boyar if (!ArchTaskExecutor.getInstance().isMainThread()) { 43734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar throw new IllegalStateException("Cannot invoke " + methodName + " on a background" 438d8ea6fa753372c38ad46211d871432363d8bd6c8Yigit Boyar + " thread"); 43934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar } 44034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar } 441c1b53ee5d095a74b84c21257fb4cd00e33f748baYigit Boyar} 442