package
android
.
arch
.
lifecycle
;
import
static
android
.
arch
.
lifecycle
.
Lifecycle
.
State
.
DESTROYED
;
import
static
android
.
arch
.
lifecycle
.
Lifecycle
.
State
.
STARTED
;
import
android
.
arch
.
core
.
executor
.
AppToolkitTaskExecutor
;
import
android
.
arch
.
core
.
internal
.
SafeIterableMap
;
import
android
.
arch
.
lifecycle
.
Lifecycle
.
State
;
import
android
.
support
.
annotation
.
MainThread
;
import
android
.
support
.
annotation
.
Nullable
;
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.
* 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.
* 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 hold by this instance
@
SuppressWarnings
({
"WeakerAccess"
,
"unused"
})
// TODO: Thread checks are too strict right now, we may consider automatically moving them to main
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
static
final
LifecycleOwner
ALWAYS_ON
=
new
LifecycleOwner
() {
private
LifecycleRegistry
mRegistry
=
init
();
private
LifecycleRegistry
init
() {
LifecycleRegistry
registry
=
new
LifecycleRegistry
(
this
);
registry
.
handleLifecycleEvent
(
Lifecycle
.
Event
.
ON_CREATE
);
registry
.
handleLifecycleEvent
(
Lifecycle
.
Event
.
ON_START
);
registry
.
handleLifecycleEvent
(
Lifecycle
.
Event
.
ON_RESUME
);
public
Lifecycle
getLifecycle
() {
private
SafeIterableMap
<
Observer
<
T
>,
LifecycleBoundObserver
>
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
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
() {
synchronized
(
mDataLock
) {
newValue
=
mPendingData
;
setValue
((
T
)
newValue
);
private
void
considerNotify
(
LifecycleBoundObserver
observer
) {
if
(!
observer
.
active
) {
// 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
(!
isActiveState
(
observer
.
owner
.
getLifecycle
().
getCurrentState
())) {
if
(
observer
.
lastVersion
>=
mVersion
) {
observer
.
lastVersion
=
mVersion
;
observer
.
observer
.
onChanged
((
T
)
mData
);
private
void
dispatchingValue
(
@
Nullable
LifecycleBoundObserver
initiator
) {
if
(
mDispatchingValue
) {
mDispatchInvalidated
=
true
;
mDispatchingValue
=
true
;
mDispatchInvalidated
=
false
;
if
(
initiator
!=
null
) {
considerNotify
(
initiator
);
for
(
Iterator
<
Map
.
Entry
<
Observer
<
T
>,
LifecycleBoundObserver
>>
iterator
=
mObservers
.
iteratorWithAdditions
();
iterator
.
hasNext
(); ) {
considerNotify
(
iterator
.
next
().
getValue
());
if
(
mDispatchInvalidated
) {
}
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.
* The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
* or {@link Lifecycle.State#RESUMED} state (active).
* If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
* automatically be removed.
* 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.
* 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.
* If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
* 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
public
void
observe
(
LifecycleOwner
owner
,
Observer
<
T
>
observer
) {
if
(
owner
.
getLifecycle
().
getCurrentState
() ==
DESTROYED
) {
LifecycleBoundObserver
wrapper
=
new
LifecycleBoundObserver
(
owner
,
observer
);
LifecycleBoundObserver
existing
=
mObservers
.
putIfAbsent
(
observer
,
wrapper
);
if
(
existing
!=
null
&&
existing
.
owner
!=
wrapper
.
owner
) {
throw
new
IllegalArgumentException
(
"Cannot add the same observer"
+
" with different lifecycles"
);
if
(
existing
!=
null
) {
owner
.
getLifecycle
().
addObserver
(
wrapper
);
wrapper
.
activeStateChanged
(
isActiveState
(
owner
.
getLifecycle
().
getCurrentState
()));
* 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
* 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
public
void
observeForever
(
Observer
<
T
>
observer
) {
observe
(
ALWAYS_ON
,
observer
);
* Removes the given observer from the observers list.
* @param observer The Observer to receive events.
public
void
removeObserver
(
final
Observer
<
T
>
observer
) {
assertMainThread
(
"removeObserver"
);
LifecycleBoundObserver
removed
=
mObservers
.
remove
(
observer
);
removed
.
owner
.
getLifecycle
().
removeObserver
(
removed
);
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.
public
void
removeObservers
(
final
LifecycleOwner
owner
) {
assertMainThread
(
"removeObservers"
);
for
(
Map
.
Entry
<
Observer
<
T
>,
LifecycleBoundObserver
>
entry
:
mObservers
) {
if
(
entry
.
getValue
().
owner
==
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");
* The value "b" would be set at first and later the main thread would override it with
* 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
) {
synchronized
(
mDataLock
) {
postTask
=
mPendingData
==
NOT_SET
;
AppToolkitTaskExecutor
.
getInstance
().
postToMainThread
(
mPostValueRunnable
);
* Sets the value. If there are active observers, the value will be dispatched to them.
* 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
protected
void
setValue
(
T
value
) {
assertMainThread
(
"setValue"
);
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
* Called when the number of active observers change to 1 from 0.
* This callback can be used to know that this LiveData is being used thus should be kept
protected
void
onActive
() {
* Called when the number of active observers change from 1 to 0.
* 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).
* 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
public
boolean
hasObservers
() {
return
mObservers
.
size
() >
0
;
* Returns true if this LiveData has active observers.
* @return true if this LiveData has active observers
public
boolean
hasActiveObservers
() {
return
mActiveCount
>
0
;
class
LifecycleBoundObserver
implements
LifecycleObserver
{
public
final
LifecycleOwner
owner
;
public
final
Observer
<
T
>
observer
;
public
int
lastVersion
=
START_VERSION
;
LifecycleBoundObserver
(
LifecycleOwner
owner
,
Observer
<
T
>
observer
) {
this
.
observer
=
observer
;
@
SuppressWarnings
(
"unused"
)
@
OnLifecycleEvent
(
Lifecycle
.
Event
.
ON_ANY
)
if
(
owner
.
getLifecycle
().
getCurrentState
() ==
DESTROYED
) {
removeObserver
(
observer
);
// immediately set active state, so we'd never dispatch anything to inactive
activeStateChanged
(
isActiveState
(
owner
.
getLifecycle
().
getCurrentState
()));
void
activeStateChanged
(
boolean
newActive
) {
if
(
newActive
==
active
) {
boolean
wasInactive
=
LiveData
.
this
.
mActiveCount
==
0
;
LiveData
.
this
.
mActiveCount
+=
active
?
1
: -
1
;
if
(
wasInactive
&&
active
) {
if
(
LiveData
.
this
.
mActiveCount
==
0
&& !
active
) {
dispatchingValue
(
this
);
static
boolean
isActiveState
(
State
state
) {
return
state
.
isAtLeast
(
STARTED
);
private
void
assertMainThread
(
String
methodName
) {
if
(!
AppToolkitTaskExecutor
.
getInstance
().
isMainThread
()) {
throw
new
IllegalStateException
(
"Cannot invoke "
+
methodName
+
" on a background"