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