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