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