P7 mobile Internet architect Advanced video (daily update) free learning please click:space.bilibili.com/474380680
preface
This article focuses on how LiveData works. If you don’t know how to use LiveData, please refer to the official documentation. Lifecycle is covered by LiveData. If you don’t already know about Lifecycle, please refer to the documentation on Lifecycle.
introduce
LiveData is a data holding class that can be observed by other components by adding observers to its changes. Unlike ordinary observers, LivaeData’s most important feature is compliance with the application lifecycle. For example, in an Activity, LivaeData does not notify the Activity(Observer) if data is updated but the Activity is already in the destroy state. Of course. LiveData has many other advantages, such as no memory leaks.
LiveData is usually used in conjunction with the ViewModel, which triggers updates of data that are notified to LiveData, which in turn notifies observers of the active state.
The principle of analysis
Let’s get straight to the code:
public class UserProfileViewModel extends ViewModel {
private String userId;
private MutableLiveData<User> user;
private UserRepository userRepo;
public void init(String userId) {
this.userId = userId;
userRepo = new UserRepository();
user = userRepo.getUser(userId);
}
public void refresh(String userId) {
user = userRepo.getUser(userId);
}
public MutableLiveData<User> getUser() {
returnuser; }}Copy the code
The above UserProfileViewModel holds a reference to MutableLiveData<User> in UserRepository and provides a method getUser() to retrieve MutableLiveData. UserRepository is responsible for fetching data from the network or database, encapsulating it into MutableLiveData and feeding it to the ViewModel.
We registered an observer for MutableLiveData<User> in the UserProfileFragment as follows:
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); String userId = getArguments().getString(UID_KEY); viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class); viewModel.init(userId); / / mark 1 viewModel. GetUser (). Observe (UserProfileFragment. This, new Observer<User>() { @Override public void onChanged(@Nullable User user) {if(user ! = null) { tvUser.setText(user.toString()); }}}); }Copy the code
Viewmodel.getuser () retrieves MutableLiveData<User>, which is our LiveData, and calls the LiveData observer method. And pass in the UserProfileFragment as a parameter. The observer() method is the entry point for our analysis. Let’s look at what the Observer () method of LiveData does:
@mainThread public void observe(@nonnull LifecycleOwner owner, @nonNULL Observer<T> Observer) {// Annotation 1if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return; } // Annotate 2 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);
}
Copy the code
As you can see, UserProfileFragment is passed in as the LifeCycleOwner parameter. If your support package version is 26.1.0 or greater, the Fragment in the Support package inherits from LifeCycleOwner by default. LifecycleOwner has access to that component’s LifeCycle and knows the LifeCycle of the UserProfileFragment component (LifeCycle is already known by default here).
Note 1: If our UserProfileFragment component is already in the Destroy state, it will return and not be added to the observer list. If not destroy, go to annotation 2 and create a LifecycleBoundObserver to save our LifecycleOwner and Observer, PutIfAbsent () then calls mobServers.putifAbsent (observer, wrapper) to place observer as key and Wrapper as value in the Map. PutIfAbsent () determines if the value already exists. Returns null otherwise. If existing is returned as null, meaning that the observer has not been added before, LifecycleBoundObserver is used as the observer of the owner lifecycle, i.e. the observer of the UserProfileFragment lifecycle.
LifecycleBoundObserver
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) { super(observer); mOwner = owner; } @Override booleanshouldBeActive() {
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); }}Copy the code
LifecycleBoundObserver inherits ObserverWrapper and implements the GenericLifecycleObserver interface. The GenericLifecycleObserver interface in turn inherits from the LifecycleObserver interface, so Lifecycle LifecycleObserver implements the LifecycleObserver interface and joins LifecycleOwner observers to perceive or actively retrieve LifecycleOwner status.
Ok, after viewing the observer, when will our LiveData notify the observer? If the User information is returned from the network, we will put the User into MutableLiveData. Here I directly simulated the network request in UserRepository as follows:
public class UserRepository {
final MutableLiveData<User> data = new MutableLiveData<>();
public MutableLiveData<User> getUser(final String userId) {
if ("xiasm".equals(userId)) {
data.setValue(new User(userId, "Xia Shengming"));
} else if ("123456".equals(userId)) {
data.setValue(new User(userId, "Ha ha ha."));
} else {
data.setValue(new User(userId, "unknow"));
}
returndata; }}Copy the code
When the getUser() method is called, we call the setValue() method of MutableLiveData to put the data into LiveData, where MutableLiveData is actually inherited from LiveData, nothing special:
public class MutableLiveData<T> extends LiveData<T> { @Override public void postValue(T value) { super.postValue(value); } @Override public voidsetValue(T value) { super.setValue(value); }}Copy the code
SetValue () must be on the main thread when placing a User, otherwise an error will be reported, while postValue does not check this and instead passes data to the main thread. Let’s look directly at the setValue() method:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
Copy the code
AssertMainThread () is called to check if it is on the main thread, then the data to be updated is assigned to mData, then the dispatchingValue() method is called and null is passed to distribute the data to various observers, such as our UserProfileFragment. Look at the dispatchingValue() method implementation:
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
//标注1
if(initiator ! = null) { considerNotify(initiator); initiator = null; }else{// Annotate 2for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break; }}}}while (mDispatchInvalidated);
mDispatchingValue = false;
}
Copy the code
As can be seen from annotation 1, the difference between null and no NULL for the dispatchingValue() parameter is that all observers are notified if null is sent, whereas only incoming observers are notified. Let’s go right to annotation 2 and notify all observers to call the duties () method by circling the mObservers, retrieving all ObserverWrapper, which is actually the LifecycleBoundObserver we mentioned above, This method is a concrete implementation of notification.
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);
}
Copy the code
If the observer is not active, will not let this observer, the last line, the observer, mObserver. OnChanged (mData (T)), Observer.mobserver is the observer that we passed in by calling the Observer () method of LiveData, and then calling the observer onChanged((T) mData) method to pass in the saved data mData, thus implementing the update. Take a look at the Observer we implemented:
viewModel.getUser().observe(UserProfileFragment.this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
if(user ! = null) { tvUser.setText(user.toString()); }}});Copy the code
If a control needs to be updated in response to user changes, the onChanged() method will do just that. At this point LiveData can be analyzed and the implementation of LiveData will depend on Lifecycle.
The original link: www.jianshu.com/p/21bb6c0f8… Ali P7 mobile Internet architect advanced video (updated daily) free learning please click: space.bilibili.com/474380680