目录结构
1.背景及livedata优劣势
2.livedata简单使用
3.livedata实现原理
1.背景及优劣势
1.优势1 感知生命周期UI活跃才刷新UI
比较常见的场景是当网络请求结果回来的时候,经常需要判断 Activity 或者 Fragment 是否已经 Destroy, 如果不是 destroy,才更新 UI
2.防止内存泄漏
livedata是在lifecycle基础上实现,当对应的Lifecycle销毁,会自动解除livedata和被观察者,比如activity的绑定关系,避免内存泄漏
3.防止数据丢失
LiveData在横竖屏切换等Configuration改变时,也能保证获取到最新数据。实现原理我们在后面的文章里面详细说。
2.简单使用
LiveData 是一个抽象类,它的实现子类有 MutableLiveData ,MediatorLiveData。常用的是 MutableLiveData。他常常结合 ViewModel 使用
依赖添加:
implementation "android.arch.lifecycle:livedata:1.1.0"
1.在viewmodle中创建 livedata
public class NameViewModel extends ViewModel {
private MutableLiveData<String> currentName;
public MutableLiveData<String> getCurrentName(){
if(currentName==null){
currentName=new MutableLiveData<>();
}
return currentName;
}
}
2.在被观察者中建立联系
通过ViewModelProviders 获取到Viewmodel然后调用model中方法调用observe传入被观察者和观察回调 ,当有变化,就会调用到onChanged方法
//需要一个观察者来观察数据
Observer observer=new Observer<String>(){
@Override
public void onChanged(String s) {
nameTextView.setText(s);
}
};
//获取到viewmodel
model= ViewModelProviders.of(this).get(NameViewModel.class);
//取出livedata完成订阅
model.getCurrentName().observe(this,observer);
接收事件LiveData提供了两种添加观察者的方法:observeForever()、observe()。使用observeForever()这个还必须手动调用remove方法移除,使用该方法 就不会管被观察者是否处于活跃状态。
3.发送事件
当需要变化,调用viewmodel 的setvalue 或者postvalue放松更新数据 ,比如下面我直接在一个按钮点击事件中,触发。
两者区别:
- setValue()要在主线程中调用, 实际上是会在调用 serValue 方法的线程回调
- postValue()既可在主线程也可在子线程中调用。
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
model.getCurrentName().postValue("XXX");
}
});
3.源码分析
1.先看livedata类的observe方法
我们在被观察者类中,调用MutableLiveData的observe方法,这个类里面定义了set postValue方法,观察方法还是在Livedata中实现:首先判断是在主线程,否则抛出异常,然后再判断当前被观察的对象状态,如果是DESTROYED状态那么return 然后封装放到一个安全的map中并绑定wrapper作为观察者,最后一行代码,还是调用lifecycle的addobserver(观察者)绑定生命周期观察。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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);
}
2.绑定后使用setValue与postValue通知观察者
可以看到下面代码最后一行里,还是调用的主线程handler实现切换到主线程,最后调用setValue
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
3.在setValue方法中调用dispatchingValue
分发value里回调用到considerNotify(initiator)方法
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;
observer.mObserver.onChanged((T) mData);
}
这个方法中主要是应该被激活状态下,调用观察者的onChanged方法 ,这样就回到我们被观察者中创建的观察回调。
网友评论