diff options
Diffstat (limited to 'androidx/lifecycle/LiveData.java')
-rw-r--r-- | androidx/lifecycle/LiveData.java | 441 |
1 files changed, 2 insertions, 439 deletions
diff --git a/androidx/lifecycle/LiveData.java b/androidx/lifecycle/LiveData.java index 8c94a950..c961d1c4 100644 --- a/androidx/lifecycle/LiveData.java +++ b/androidx/lifecycle/LiveData.java @@ -1,441 +1,4 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +//LiveData interface for tests package androidx.lifecycle; - -import static androidx.lifecycle.Lifecycle.State.DESTROYED; -import static androidx.lifecycle.Lifecycle.State.STARTED; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.arch.core.internal.SafeIterableMap; -import androidx.arch.core.executor.ArchTaskExecutor; - -import java.util.Iterator; -import java.util.Map; - -/** - * LiveData is a data holder class that can be observed within a given lifecycle. - * This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and - * this observer will be notified about modifications of the wrapped data only if the paired - * LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is - * {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED}. An observer added via - * {@link #observeForever(Observer)} is considered as always active and thus will be always notified - * about modifications. For those observers, you should manually call - * {@link #removeObserver(Observer)}. - * - * <p> An observer added with a Lifecycle will be automatically removed if the corresponding - * Lifecycle moves to {@link Lifecycle.State#DESTROYED} state. This is especially useful for - * activities and fragments where they can safely observe LiveData and not worry about leaks: - * they will be instantly unsubscribed when they are destroyed. - * - * <p> - * In addition, LiveData has {@link LiveData#onActive()} and {@link LiveData#onInactive()} methods - * to get notified when number of active {@link Observer}s change between 0 and 1. - * This allows LiveData to release any heavy resources when it does not have any Observers that - * are actively observing. - * <p> - * This class is designed to hold individual data fields of {@link ViewModel}, - * but can also be used for sharing data between different modules in your application - * in a decoupled fashion. - * - * @param <T> The type of data held by this instance - * @see ViewModel - */ -public abstract class LiveData<T> { - private final Object mDataLock = new Object(); - static final int START_VERSION = -1; - private static final Object NOT_SET = new Object(); - - private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = - new SafeIterableMap<>(); - - // how many observers are in active state - private int mActiveCount = 0; - private volatile Object mData = NOT_SET; - // when setData is called, we set the pending data and actual data swap happens on the main - // thread - private volatile Object mPendingData = NOT_SET; - private int mVersion = START_VERSION; - - private boolean mDispatchingValue; - @SuppressWarnings("FieldCanBeLocal") - private boolean mDispatchInvalidated; - private final Runnable mPostValueRunnable = new Runnable() { - @Override - public void run() { - Object newValue; - synchronized (mDataLock) { - newValue = mPendingData; - mPendingData = NOT_SET; - } - //noinspection unchecked - setValue((T) newValue); - } - }; - - private void considerNotify(ObserverWrapper observer) { - if (!observer.mActive) { - return; - } - // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. - // - // we still first check observer.active to keep it as the entrance for events. So even if - // the observer moved to an active state, if we've not received that event, we better not - // notify for a more predictable notification order. - if (!observer.shouldBeActive()) { - observer.activeStateChanged(false); - return; - } - if (observer.mLastVersion >= mVersion) { - return; - } - observer.mLastVersion = mVersion; - //noinspection unchecked - observer.mObserver.onChanged((T) mData); - } - - private void dispatchingValue(@Nullable ObserverWrapper initiator) { - if (mDispatchingValue) { - mDispatchInvalidated = true; - return; - } - mDispatchingValue = true; - do { - mDispatchInvalidated = false; - if (initiator != null) { - considerNotify(initiator); - initiator = null; - } else { - for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = - mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { - considerNotify(iterator.next().getValue()); - if (mDispatchInvalidated) { - break; - } - } - } - } while (mDispatchInvalidated); - mDispatchingValue = false; - } - - /** - * Adds the given observer to the observers list within the lifespan of the given - * owner. The events are dispatched on the main thread. If LiveData already has data - * set, it will be delivered to the observer. - * <p> - * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED} - * or {@link Lifecycle.State#RESUMED} state (active). - * <p> - * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will - * automatically be removed. - * <p> - * When data changes while the {@code owner} is not active, it will not receive any updates. - * If it becomes active again, it will receive the last available data automatically. - * <p> - * LiveData keeps a strong reference to the observer and the owner as long as the - * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to - * the observer & the owner. - * <p> - * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData - * ignores the call. - * <p> - * If the given owner, observer tuple is already in the list, the call is ignored. - * If the observer is already in the list with another owner, LiveData throws an - * {@link IllegalArgumentException}. - * - * @param owner The LifecycleOwner which controls the observer - * @param observer The observer that will receive the events - */ - @MainThread - public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { - assertMainThread("observe"); - if (owner.getLifecycle().getCurrentState() == DESTROYED) { - // ignore - return; - } - LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); - ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); - if (existing != null && !existing.isAttachedTo(owner)) { - throw new IllegalArgumentException("Cannot add the same observer" - + " with different lifecycles"); - } - if (existing != null) { - return; - } - owner.getLifecycle().addObserver(wrapper); - } - - /** - * Adds the given observer to the observers list. This call is similar to - * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which - * is always active. This means that the given observer will receive all events and will never - * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop - * observing this LiveData. - * While LiveData has one of such observers, it will be considered - * as active. - * <p> - * If the observer was already added with an owner to this LiveData, LiveData throws an - * {@link IllegalArgumentException}. - * - * @param observer The observer that will receive the events - */ - @MainThread - public void observeForever(@NonNull Observer<? super T> observer) { - assertMainThread("observeForever"); - AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); - ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); - if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) { - throw new IllegalArgumentException("Cannot add the same observer" - + " with different lifecycles"); - } - if (existing != null) { - return; - } - wrapper.activeStateChanged(true); - } - - /** - * Removes the given observer from the observers list. - * - * @param observer The Observer to receive events. - */ - @MainThread - public void removeObserver(@NonNull final Observer<? super T> observer) { - assertMainThread("removeObserver"); - ObserverWrapper removed = mObservers.remove(observer); - if (removed == null) { - return; - } - removed.detachObserver(); - removed.activeStateChanged(false); - } - - /** - * Removes all observers that are tied to the given {@link LifecycleOwner}. - * - * @param owner The {@code LifecycleOwner} scope for the observers to be removed. - */ - @SuppressWarnings("WeakerAccess") - @MainThread - public void removeObservers(@NonNull final LifecycleOwner owner) { - assertMainThread("removeObservers"); - for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) { - if (entry.getValue().isAttachedTo(owner)) { - removeObserver(entry.getKey()); - } - } - } - - /** - * Posts a task to a main thread to set the given value. So if you have a following code - * executed in the main thread: - * <pre class="prettyprint"> - * liveData.postValue("a"); - * liveData.setValue("b"); - * </pre> - * The value "b" would be set at first and later the main thread would override it with - * the value "a". - * <p> - * If you called this method multiple times before a main thread executed a posted task, only - * the last value would be dispatched. - * - * @param value The new value - */ - protected void postValue(T value) { - boolean postTask; - synchronized (mDataLock) { - postTask = mPendingData == NOT_SET; - mPendingData = value; - } - if (!postTask) { - return; - } - ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); - } - - /** - * Sets the value. If there are active observers, the value will be dispatched to them. - * <p> - * This method must be called from the main thread. If you need set a value from a background - * thread, you can use {@link #postValue(Object)} - * - * @param value The new value - */ - @MainThread - protected void setValue(T value) { - assertMainThread("setValue"); - mVersion++; - mData = value; - dispatchingValue(null); - } - - /** - * Returns the current value. - * Note that calling this method on a background thread does not guarantee that the latest - * value set will be received. - * - * @return the current value - */ - @Nullable - public T getValue() { - Object data = mData; - if (data != NOT_SET) { - //noinspection unchecked - return (T) data; - } - return null; - } - - int getVersion() { - return mVersion; - } - - /** - * Called when the number of active observers change to 1 from 0. - * <p> - * This callback can be used to know that this LiveData is being used thus should be kept - * up to date. - */ - protected void onActive() { - - } - - /** - * Called when the number of active observers change from 1 to 0. - * <p> - * This does not mean that there are no observers left, there may still be observers but their - * lifecycle states aren't {@link Lifecycle.State#STARTED} or {@link Lifecycle.State#RESUMED} - * (like an Activity in the back stack). - * <p> - * You can check if there are observers via {@link #hasObservers()}. - */ - protected void onInactive() { - - } - - /** - * Returns true if this LiveData has observers. - * - * @return true if this LiveData has observers - */ - @SuppressWarnings("WeakerAccess") - public boolean hasObservers() { - return mObservers.size() > 0; - } - - /** - * Returns true if this LiveData has active observers. - * - * @return true if this LiveData has active observers - */ - @SuppressWarnings("WeakerAccess") - public boolean hasActiveObservers() { - return mActiveCount > 0; - } - - class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { - @NonNull final LifecycleOwner mOwner; - - LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { - super(observer); - mOwner = owner; - } - - @Override - boolean shouldBeActive() { - return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); - } - - @Override - public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { - if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { - removeObserver(mObserver); - return; - } - activeStateChanged(shouldBeActive()); - } - - @Override - boolean isAttachedTo(LifecycleOwner owner) { - return mOwner == owner; - } - - @Override - void detachObserver() { - mOwner.getLifecycle().removeObserver(this); - } - } - - private abstract class ObserverWrapper { - final Observer<? super T> mObserver; - boolean mActive; - int mLastVersion = START_VERSION; - - ObserverWrapper(Observer<? super T> observer) { - mObserver = observer; - } - - abstract boolean shouldBeActive(); - - boolean isAttachedTo(LifecycleOwner owner) { - return false; - } - - void detachObserver() { - } - - void activeStateChanged(boolean newActive) { - if (newActive == mActive) { - return; - } - // immediately set active state, so we'd never dispatch anything to inactive - // owner - mActive = newActive; - boolean wasInactive = LiveData.this.mActiveCount == 0; - LiveData.this.mActiveCount += mActive ? 1 : -1; - if (wasInactive && mActive) { - onActive(); - } - if (LiveData.this.mActiveCount == 0 && !mActive) { - onInactive(); - } - if (mActive) { - dispatchingValue(this); - } - } - } - - private class AlwaysActiveObserver extends ObserverWrapper { - - AlwaysActiveObserver(Observer<? super T> observer) { - super(observer); - } - - @Override - boolean shouldBeActive() { - return true; - } - } - - private static void assertMainThread(String methodName) { - if (!ArchTaskExecutor.getInstance().isMainThread()) { - throw new IllegalStateException("Cannot invoke " + methodName + " on a background" - + " thread"); - } - } +public class LiveData<T> { } |