Android works JetPack architecture LiveData components of (a)

Ali P7 mobile Internet architect, Advanced Video (Daily update) for free learning, please click: https://space.bilibili.com/474380680

Foreword

The main principle of this article to explain LiveData work, do not know if LiveData How, then, please refer to the official documentation .
LiveData explanation related to the Lifecycle of knowledge, if you do not know LifeCycle, please refer to the documentation LifeCycle introduction .

Introduction

LiveData is a data holding class, it can be observed by adding the observer changing other components. Unlike ordinary observer, its most important feature is to comply with the life cycle of the application, such as in the Activity if the data has been updated but Activity destroy the state, LivaeData will not notice Activity (observer). of course. LiveData there are many advantages, such as will not cause memory leaks.

LiveData often with ViewModel to use, ViewModel responsible for triggering the update data, update notification to LiveData, then LiveData then notify the active observer status.

Principle Analysis

Direct look at the code below:

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() {
        return user;
    }

}

Above the internal holder UserRepository UserProfileViewModel MutableLiveData <User> reference, and provides a method of obtaining MutableLiveData getUser of (), UserRepository responsible for getting data from a network or database and then supplied to the packaged into MutableLiveData ViewModel.

We UserProfileFragment for MutableLiveData <User> Register observer, 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);
    //标注1
    viewModel.getUser().observe(UserProfileFragment.this, new Observer<User>() {
        @Override
        public void onChanged(@Nullable User user) {
            if (user != null) {
                tvUser.setText(user.toString());
            }
        }
    });
}

Look at the label 1, viewModel.getUser () to get MutableLiveData <User> is our LiveData, then call the method LiveData observer and the UserProfileFragment passed as an argument to go. observer () method is the entrance of our analysis, then we see LiveData of the observer () methods are done:

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    //标注1
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //标注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);
}

You can see, UserProfileFragment as LifeCycleOwner parameter passed in, if your support package version greater than or equal 26.1.0, Fragment default support package inherited from LifecycleOwner, and LifecycleOwner available to the component LifeCycle, also know lifecycle UserProfileFragment component (here we have to find out about the default lifeCycle a).

Look at the label 1, if we UserProfileFragment components already destroy the state, it will direct return, it will not be added to the ranks of the observer. If not destroy the state, went to the mark at 2, a new LifecycleBoundObserver save our LifecycleOwner and observer up, and then call mObservers.putIfAbsent (observer, wrapper), respectively, as the observer and the wrapper key and value into the Map, putIfAbsent () The method would have been able to determine if the value exists, returns, otherwise it returns null.
If the return existing null, the description had not been added to this observer, the observer will LifecycleBoundObserver as the owner of the life cycle, that is, as UserProfileFragment lifecycle observer.

We look LifecycleBoundObserver Source:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<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);
    }
}

Code is not much, LifecycleBoundObserver inherited from ObserverWrapper and implemented GenericLifecycleObserver interface, and the interface has inherited from LifecycleObserver GenericLifecycleObserver interface, then Lifecycle according to the characteristics of the interface and achieve the LifecycleObserver join LifecycleOwner observer where you can perceive or take the initiative to obtain the status of LifecycleOwner .

Well, after reading the observer, then our LiveData when it will inform the viewer? I do not think, certainly the data update, and update the data of our own code control, after such request the network to return to the User Information, we will take the initiative in the User into MutableLiveData, here I request UserRepository direct analog network 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, "夏胜明"));
        } else if ("123456".equals(userId)) {
            data.setValue(new User(userId, "哈哈哈"));
        } else {
            data.setValue(new User(userId, "unknow"));
        }
        return data;
    }
}

When calling getUser () method, we call MutableLiveData the setValue () method to put data into LiveData in here MutableLiveData actually inherited from LiveData, nothing special:

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

setValue () must be in the main thread, otherwise it will error when placed User, and postValue do not have this check, but will pass the data to the main thread. We look directly setValue () method:

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

First call assertMainThread () to check whether the main thread, and then assign the data to be updated mData, then call dispatchingValue () method and passing null, data will be distributed to various observers, such as our UserProfileFragment. Look 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 {
            //标注2
            for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

As can be seen from the marked 1, dispatchingValue () and does not pass null parameters passed difference is that if passed null null will notify all of its observers, whereas only notification of incoming observer. We look directly labeled 2, notify all observers by traversing mObservers, all ObserverWrapper get, in fact, we mentioned above LifecycleBoundObserver, inform observers call considerNotify () the specific method, which is to inform achieved.

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);
}

If the observer is not active, the viewer will not notice this, look at the last line, observer.mObserver.onChanged ((T) mData), observer.mObserver is what we call the observer LiveData () method passed Observer, then call Observer of onChanged ((T) mData) method to save the incoming data mData, also implements the update. In the realization of our look Observer:

viewModel.getUser().observe(UserProfileFragment.this, new Observer<User>() {
    @Override
    public void onChanged(@Nullable User user) {
        if (user != null) {
            tvUser.setText(user.toString());
        }
    }
});

If any control to change and update according to user, you deal with it in onChanged () method in. Here, LiveData have been able to analyze over, in fact, LiveData implementation still have to rely on the Lifecycle.

Original link: https://www.jianshu.com/p/21bb6c0f8a5a
Ali P7 mobile Internet architect, Advanced Video (Daily update) for free learning, please click: https://space.bilibili.com/474380680

Guess you like

Origin www.cnblogs.com/Android-Alvin/p/12109373.html