LiveData source code analysis (Part 1)
##What is LiveData
Official document explanation link: https://developer.android.google.cn/reference/androidx/lifecycle/LiveData?hl=en
LiveData is a class of data holders that can be observed in a given life cycle. This means that the Observer can add a lifecycle owner in pairs with the, and only when the paired lifecycle owner is active will the Observer be notified of the modification of the packaging data. If the lifecycle owner status is lifecycle State. Started or, it is considered active lifecycle State. RESUMED. The via Observer (Observer) added by the Observer is considered to be always active, so you will always be notified of the modification. For these observers, you should manually call removeObserver(Observer).
If the corresponding lifecycle is moved to lifecycle State. If the state is destroyed, the observer added with the life cycle will be automatically deleted. This is particularly useful for activities and fragments that can safely observe LiveData without worrying about leaks: when they are destroyed, they will be immediately unsubscribed.
In addition, when the number of active changes between 0 and 1, LiveData has onActive() and onInactive() notification methods Observer. This allows LiveData to free up a lot of resources without any active observers.
This class is designed to accommodate a single data field ViewModel, but can also be used to share data between different modules in an application in a separate manner
Advantages of using LiveData
Using LiveData has the following advantages (reference Android development documents):
-
Ensure that the interface complies with the data status
LiveData follows the observer mode. LiveData notifies when the lifecycle state changes Observer Object. You can integrate the code to update the interface in these Observer objects. It can happen every time the interface changes, not every time the Observer updates the interface.
-
No memory leaks
The observer is bound to Lifecycle Object and clean itself up after its associated lifecycle is destroyed.
-
No crash due to Activity stop
If the observer's lifecycle is inactive (such as returning an Activity in the stack), it will not receive any LiveData events.
-
You no longer need to manually process the lifecycle
The interface component only observes relevant data and will not stop or resume observation. LiveData will automatically manage all these operations because it can perceive the relevant lifecycle state changes when observing.
-
Data is always up-to-date
If the lifecycle becomes inactive, it receives the latest data when it becomes active again. For example, an Activity that used to be in the background will receive the latest data immediately after returning to the foreground.
-
Appropriate configuration changes
If an Activity or Fragment is recreated due to configuration changes, such as device rotation, it will immediately receive the latest available data.
-
shared resource
You can extend using single instance mode LiveData Object to encapsulate system services so that they can be shared in applications. The LiveData object is connected to the system service once, and then any observer who needs the corresponding resources only needs to observe the LiveData object. For details, see Extend LiveData.
For example: to process the login result, you need to check the current status of the activity first
public void login(){ String name=""; String password=""; loginModel.login(name,password,new Callback<User>(){ public void onSuccess(User user){ if(!isDestroyed()){ //todo handles the business of successful login } } public void onFailure(int code,String msg){ if(!isDestroyed()){ //todo handles the business of login failure } } }) }
Cancel asynchronous task in activity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onDestroy(){ super.onDestroy(); mainModel.cancelTask() } }
API usage
The main categories are
The official documents are provided. Students who can't use LiveData can learn from the official documents first
https://developer.android.com/topic/libraries/architecture/livedata#java
Let's analyze the source code of LiveData
First of all, let's analyze the calling process of LiveData setValue source code we often use
//setValue notifies the observer of data changes protected void setValue(T value) { //Is check the main thread assertMainThread("setValue"); //Mark current version number mVersion++; //Cache current notification data mData = value; //send data dispatchingValue(null); }
Analysis of dispatchingValue method
void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { //If sending ends, the current sending flag is invalid mDispatchInvalidated = true; return; } //Mark distributing data mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { //loop all observers send data for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { //Resolve notification considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); //Mark the sending status as false and the sending task ends mDispatchingValue = false; }
considerNotify method analysis
private void considerNotify(ObserverWrapper observer) { //Check whether the observer is active if (!observer.mActive) { //The inactive state ends sending data to this observer 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 the last data version received by the observer is greater than or equal to the version of the currently transmitted data, the transmission of the currently transmitted data for this observation will be ended if (observer.mLastVersion >= mVersion) { return; } //Update the number of last versions received by this observer observer.mLastVersion = mVersion; //The object of the observer is decorated to get the observer object and then the onChanged is notified to change the data. This onChanged method is the callback method of the upper level LiveData that registers a Observer observer interface. //noinspection unchecked observer.mObserver.onChanged((T) mData); }
Let's analyze the calling process of LiveData observe
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { //Must be registered in the main thread assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // If the current life cycle of ignore is in the status of destruction, the registration ends return; } //Wrap an observer with the ability to perceive the life cycle through lifecycle owner and observer LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); //check whether the current observer is registered ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { //Exception thrown if registered throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } //Register the wrapped observer in componentactivity lifecycle registry mobservermap owner.getLifecycle().addObserver(wrapper); }
Observer of life cycle capability packaging class LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } @Override boolean shouldBeActive() { //State. STARTED State. Returned true return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { //Callback when lifecycle changes if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { //Destroy status unsubscribe removeObserver(mObserver); return; } //Notification activation status changed activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } }
To summarize
- The observer is packaged as a lifecycle bound observer wrapper
- The Lifecycle mObserverMap of the lifecycle owner is added to the wrapper
- When the lifecycle changes, the onStateChanged method of LifecycleBoundObserver will be notified
Analysis of activeStateChanged method of ObserverWrapper
void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } // immediately set active state, so we'd never dispatch anything to inactive // owner mActive = newActive; //Mark whether it is currently active boolean wasInactive = LiveData.this.mActiveCount == 0; //Calculate the number of currently active LiveData observers active + 1 inactive - 1 LiveData.this.mActiveCount += mActive ? 1 : -1; //LiveData is inactive and the current activity is activated if (wasInactive && mActive) { //LiveData is activated and called onActive(); } if (LiveData.this.mActiveCount == 0 && !mActive) { //LiveData inactive call onInactive(); } if (mActive) { //Resend data when activated dispatchingValue(this); } }
To summarize, after receiving the life cycle change notification, I did the following things
- LiveData is activated and onActive is called to notify the business layer that LiveData has been observed
- When LiveData becomes inactive, call onInactive to notify the business layer that LiveData is idle and some resources can be released
- The observer is activated, and the data in LiveData will be notified again
summary
- LiveData is an implementation based on observer mode
- Only when the observer is active (Lifecycle State.STARTED | State.RESUMED) can he receive the message sent by LiveData
- After activity fragment deleted, the observer will not receive a message. The asynchronous task notifies the UI update through LiveData and does not need to pay attention to the UI status
- Call setValue. If the current observer is inactive, the data will be temporarily stored. When the observer is set to the active state, the observer will be automatically notified of data update
Some scenarios that LiveData can solve
###Scenario 1 topic details like topic comments
Page A (topic list)
- Display: number of item likes
- Display: item like status
Page B (topic details)
- Display: number of likes
- Display: like status
- Behavior: like
Enter page B. the current user does not like it
Business:
- The user likes the operation, the number of likes on page B + 1, and the like status lights up
- Return to page A. the number of likes for this topic is + 1, and the like status is on
LiveData solution:
Create a LiveData of topic data
- Add an observer of topic data to page A
- After the business operation of page B is completed, use LiveData to send the changed topic data
- Page B returns to page A, which becomes active, and then receives the topic data sent before page B
- Page A replaces the old topic data and updates the list UI
You might have thought before you had LiveData
- EventBus: external libraries need to be added. Lifecycle registration and deregistration need to be handled
- Use the api to register the broadcast, but not to register the broadcast
- java observer api: it is troublesome to implement some classes. It also needs to handle the registration and deregistration of life cycle observers
By comparing the methods of LiveData, we can see that the LiveData scheme is relatively simple and clear
- Maintenance free life cycle
- Register the observer and notify the observer
- Focus on business processing
Scenario 2 app Download
There will be no details here
Scene 3 Music Player
The current owner is audio distribution, and I am mainly responsible for the watch end business
The audio playback UI update business is going to be reconstructed with LiveData (currently using EventBus)
Problem | solution
Switching topics leads to page reconstruction problems
Scenario: click the item in the news list, and a dialog will pop up to show the details. Then close the dialog, the ide will simulate killing the application, switch back to the application from the application taskbar, and the dialog page will be displayed
There are two classes 1 NewListActivity,2.NewViewModel
NewListActivity
public class NewListActivity ...{ private NewViewModel vm; public void initData(){ vm=new ViewModelProvider(this).get(NewViewModel.java) vm.liveData.observe(this,new Observer<Object>() { public void onChanged(Object obj){ //showDialog } }); } }
NewViewModel
public class NewViewModel..{ public LiveData liveData.. public loadNewDetail(){ //Request news details //liveData.setValue() notification update UI } }
Reason: the page is destroyed first and then rebuilt, so the Observer will be removed and the rebuilt Observer will be added again. It can be seen from the source code that the newly registered Observer will receive the notification of LiveData.
next
The second part of LiveData source code analysis intends to analyze the extension of LiveData
- Transformations map switchMap source code analysis
- Source code analysis of subclass MediatorLiveData