preface
Before you can understand LiveData and learn how it works, Lifecycle needs to be understood and understood otherwise some parts of the following may be difficult to understand.
Portal – Lifecycle
convention
Observer: LifecycleOwner: LifecycleOwner: Observer: LifecycleOwner: LifecycleOwner
What is LiveData
Source code for LiveData annotation, personal feeling explained very in place
/**
* 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, ifIts state is */ meaning roughly as follows: Data held by LiveData can be perceived. In LiveData, the observer is paired with the owner (except, of course, more on that later). The observer is notified when the LiveData held wrapped data changes while in the active state. The owner State is considered active when it is state. STARTED or state. RESUME.Copy the code
To put it simply, LiveData serves as a medium to hold data and notify the observer who monitors the owner and is in the active state to respond when the data changes.
Case # #
public class MyData extends LiveData<String> {
private static final String TAG = "T-MyData";
public MyData() {setValue("hi");
}
@Override
protected void onActive() {
super.onActive();
Log.d(TAG, "onActive ");
}
@Override
protected void onInactive() {
super.onInactive();
Log.d(TAG, "onInactive ");
}
public void changeValue(String value){
setValue(value); }}Copy the code
public class MainActivity extends AppCompatActivity {
private static final String TAG = "T-MainActivity";
MyData data = new MyData();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
data.changeValue(data.getValue() + "~"); }}); data.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String value) { Log.d(TAG,"onChanged: "+ value ); }}); }}Copy the code
Case behavior: LiveData holds String data and is observed by observers during the MainActivity(owner) life cycle. String starts with “hi”, and every time you click the button on the page String adds “~” to the original splice. When the data changes, onChanged() accepts the changed data. Let MainActiviy enter the invisible status log after clicking three times
Data is sensed from the log, and onActive() and onInactive() are triggered, which will be explained below.
The principle of
The important function
For the use of LiveData is important and contains the need to note, singled out for warning
- setValue()
protected void setValue(T value) {
assertMainThread("setValue"); . }Copy the code
This function sets the data in LiveData and executes it in the main thread
- postValue()
protected void postValue(T value) {
.....
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
Copy the code
-getValue() : Retrieves LiveData, but does not guarantee that it will receive the latest data (for example, updating data in an asynchronous thread was delayed)
## As described earlier in the registration process, Onwer and the observer appear in pairs. Register via Observe. In addition, registration is also available through observeForever, which differs from the Observer. Observe mode is explained here and observeForver is compared later.
- LiveData.obsever()
@MainThread public void observe(@NonNull LifecycleOwner owner, @nonnull Observer<T> Observer) {// Owner is in the Destroy state and no registration is requiredif (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return; } // LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); // An observer is only for one onwerif(existing ! = null && ! existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if(existing ! = null) {return; LifecycleRegistry owner.getLifecycle().addobServer (wrapper); }Copy the code
According to the code, during registration, the owner status is checked to see if it is appropriate, and then the owner is bound to the observer. From the exception thrown, it can be seen that the relationship between the owner and the observer is one-to-many. Then pass the wrapped ObserverWrapper to LifecycleRegistry, which ensures that the message will be received by the ObserverWrapper when the state. Event Event arrives. (Lifecycle knowledge, forget to go here -> portal)
The binding process
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) { super(observer); mOwner = owner; }... }Copy the code
private abstract class ObserverWrapper { final Observer<T> mObserver; ObserverWrapper(Observer<T> observer) { mObserver = observer; }... }Copy the code
Part of LifecycleBoundObserver and its parent ObserverWrapper class are posted here, and you can see that they hold owner and observer information, respectively.
At this point, the registration process is complete. The process is simple. Make a summary
- Bind owner and observer, and collect information into LifecycleBoundObserver
- LifecycleBoundObserver is handed over to LifecycleRegistry for registration so that events can be received as they come in
Lifecycle knowledge will know that the Event will eventually be processed by the GenericLifecycleObserver implementation class as a relay to the specific observer. As you can see from the previous code screenshots, LifecycleBoundObserver is the GenericLifecycleObserver implementation class and therefore receives events.
public interface GenericLifecycleObserver extends LifecycleObserver {
void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}
Copy the code
The GenericLifecycleObserver is an observer for Lifecycle and an actual observer for Lifecycle. There is a distinction between responsibility and responsibility so that responsibility can be placed on the shoulder. To review the principles of Lifecycle, the code location is as follows
The current position - LifecycleRegistry. AddObserver () - ObserverWithState () - Lifecycling. GetCallback (static) GenericLifecycleObserver getCallback(Object object) { .....if (object instanceof GenericLifecycleObserver) {
return(GenericLifecycleObserver) object; }... }Copy the code
As you can see, if the observer (for Lifecycle) is a GenericLifecycleObserver, the Event Event is handled by the observer (for Lifecycle), and this type of observer does all the work described above. (can be viewed in the Lifecycle system SingleGeneratedAdapterObserver will be clear at a glance, if forget portal, is important for understanding).
The current position - LifecycleBoundObserver. OnStateChanged () @ Override public void onStateChanged (LifecycleOwnersource, Lifecycle.Event Event) {// Check the owner statusif(mowner.getLifecycle ().getCurrentState() == DESTROYED) {return; ActiveStateChanged (shouldBeActive());} // Check whether the observer is in active state and react accordingly }} current position - lifecyCleBoundobServer.shouldBeActive () @override BooleanshouldBeActive() {
// trueIndicates that the owner is at least in the State.STARTEDreturn mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
Copy the code
Don’t explain
ActiveStateChanged () void activeStateChanged(Boolean newActive) {// No processing in the same stateif (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive // owner // Update status mActive = newActive; / / whether there is in the active state observer of Boolean wasInactive = LiveData. Enclosing mActiveCount = = 0; LiveData.this.mActiveCount += mActive ? 1:1; 1 ️ if (wasInactive && mActive) {onActive(); } 2 ⃣ ️ if (LiveData. Enclosing mActiveCount = = 0 &&! mActive) { onInactive(); } if (mActive) {dispatchingValue(this); }}Copy the code
The code 1 and 2 indicate that the owner is in the State.STARTED or state. CREATED State. The observer is in the active State, while state. INITIALIZED or state. CREATED State is inActive.
Data to inform
Lifecycleboundobserver.dispatchingvalue () private void dispatchingValue(@nullable ObserverWrapper initiator) {if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if(initiator ! = null) {// Try to notify the observer (initiator); initiator = null; }else {
for(Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {// let the observer notice (iterator.next().getvalue ()));if (mDispatchInvalidated) {
break; }}}}while (mDispatchInvalidated);
mDispatchingValue = false;
}
Copy the code
Just know that dispatchingValue() will try to notify the observer, depending on the observer.
-lifecycleBoundobServer.dispatchingValue () -- considerNotify() private void considerNotify(ObserverWrapper Observer) {// The observer is in theinThe Active stateif(! observer.mActive) {return; } / / source code comments for, check whether the observer is in response to the change of meaning is that, although the observer may / / is in a state of the response, but this did not receive the Event notification, it is best not to notice to maintain good inform order / / / / here can be understood as, prevent element of chaos caused by the possible memory leak problem, Also to ensure that // only one notification is made in the same stateif(! Observer. ShouldBeActive ()) {/ / back to the starting point of the trigger considerNotify here, is to wait for, repair, disorderly observer. ActiveStateChanged (false);
return; } // Data does not change without notificationif (observer.mLastVersion >= mVersion) {
return; } observer.mLastVersion = mVersion; / / observer callback observer. MObserver. OnChanged (mData (T)); }Copy the code
In addition to the explanation in the comments in the code, it is important to know that LiveData has a private variable, mVersion, which maintains the version of the data it holds and notifies it only when a version update is detected.
Also, setValue() can trigger notice ()
protected void setValue(T value) {
// 在主线程执行
assertMainThread("setValue"); // data version update mVersion++; mData = value; / / notice dispatchingValue (null); }Copy the code
The distribution process is concluded as follows:
- ObserverWrapper and subclasses hold owner and observer information and implement GenericLifecycleObserver to handle the Event itself
- Event When the Event arrives, LiveData will be processed according to the owner’s State. OnActive () will be called when the observer is in active State. Call onInactive() when inActive
- LiveData notifies observers in the active state when the owner life cycle changes or when data is updated
remind
The article doesn’t end there. For LiveData, registration prevention provides registration for observeForever as well as observeForever
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
public void observeForever(@NonNull Observer<T> observer)
Copy the code
From the parameters alone, it is easy to think that the observer is not bound to the specified onwer. From the previous analysis, the observer is also destroyed when the ONwer is destroyed. Therefore, it can be inferred that compared with the Observe registration method, ObserveForever registers observers with a broader life cycle of their own.
- 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.
ObserveForever this method is similar to observeForever, but the observer will always receive the event and will not be automatically removed.
Visible, in the use and principle of the need to do screening.
case
public class MainActivity extends AppCompatActivity {
private static final String TAG = "T-MainActivity";
MyData data = BActivity.data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
data.changeValue(data.getValue() + "~"); }}); findViewById(R.id.startBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, BActivity.class); startActivity(intent); }}); }}Copy the code
public class BActivity extends AppCompatActivity {
private static final String TAG = "T-BActivity";
public static MyData data = new MyData();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
data.observeForever(new Observer<String>() {
@Override
public void onChanged(@Nullable String value) {
Log.d(TAG, "I'am still here , value is : "+ value); }}); } @Override public voidonBackPressed() { super.onBackPressed(); finish(); }}Copy the code
Page description: Static object with LiveData in B page, B will be destroyed when the return key is pressed. The Main page has a Click Me button that concatenates LiveData data with a “~” when clicked, and another button to launch page B. Page operation: start B from Main, press the back button, Click Click Me button for many times, the log is as follows
Easy to verify, the observer still exists.
ObserveForever principle
public void observeForever(@NonNull Observer<T> observer) { AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); The LifecycleBoundObserver class cannot be LifecycleBoundObserver except for an inspection similar to Observe ()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);
}
Copy the code
Code, the process is similar, but observeForever () does not use observe () USES LifecycleBoundObserver, and failed to pass the Lifecycle. LifecycleRegistry register, It is possible to guess that observers registered in this way are not bound to the actual owner (as previously mentioned). The answer can be found in AlwaysActiveObserver
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true; }}Copy the code
AlwaysActiveObserver is a simple method, shouldBeActive() and observeForever(). Observe with observeForever()
- The Lifycycle mechanism is not utilized, so there is no awareness of the life cycle
- The behavior is simple listening and callbacks in simple observer mode
- There is a risk of memory leakage. Remove it manually
Simple schematic diagram
The picture shows the reception process as well as the registration process and the perception process because understanding Lifecycle is really important to understanding
prompt
This is the end of the article, the following part for the episode, interested welcome to read
episode
The advantage of LiveData is that it makes data aware of changes in the life cycle and enables data sharing. In the process of learning LiveData, I have looked up some corresponding blog posts, among which I am very concerned that some places point out that singletons are used to make LiveData realize data sharing without necessary explanation, which is easy to cause confusion and misunderstanding. Singletons are just a form of helplessness, the worst solution. The essence of Data sharing in LiveData is to leverage observers, not overly long life cycles. In addition, LiveData needs to solve the problem of how components with life cycle adjust their state according to the necessary or important data state in their life cycle, and realize the decoupling of life cycle monitoring and data state.
I am singleton, I am self – sharing, I still need to feel 0 0?
(I used static LiveData in 🌰 only for presentation purposes, not in practice)
Thanks to Tu ge for his guidance and q&A
Next: Data sharing and Persistence, the use and principle of ViewModel