学习下LiveData
目录
- 如何使用
- 源码解析
- 粘性事件
1、使用
LiveData是Google的提供标准化开发的组件之一
主要就是在页面中传递数据在Activity的Fragment中,一个Fragment改变了数据,可以通知到另一个Fragment
当屏幕旋转时候,会自动通知组件推送最后一次数据
并且可以感知生命周期,帮开发者避免一些因Fragment销毁而导致的空指针问题
用法其实很简单
//定一个MutableLiveData
val name = MutableLiveData()
//在需要的地方进行订阅
userBean.observe(this,{ it->
//显示数据
})
//在需要的地方 发送数据
name.value = "数据改变了"
通常会放在ViewModel中,贴一下部分代码
//定义一个ViewModel
class UserViewModel :ViewModel() {
val name = MutableLiveData()
fun setName(str: String) {
name.value = str
}
}
//定义2个Fragment 在同一个Activity上
//FragmentA
class FragmentA : Fragment() {
//定义ViewModel
private lateinit var model: UserViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model = ViewModelProvider(requireActivity()).get(UserViewModel::class.java)
//忽略xml界面,设置按钮点击事件
btn.setOnClickListener {
model.setName("abc")
}
}
}
//FragmentB
class FragmentB : Fragment() {
//定义ViewModel
private lateinit var model: UserViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model = ViewModelProvider(requireActivity()).get(UserViewModel::class.java)
//忽略xml,这里进行订阅数据有变化时候 执行onChanged方法
model.name.observe(requireActivity(),object:Observer{
override fun onChanged(t: String?) {
tv_name.text = t
}
})
}
}
当点击按钮的时候,setName
执行赋值方法通知订阅 执行 onChanged方法。
第一次看到会比较奇怪,为什么两个对象通过 ViewModelProvider
赋值,之后订阅就能执行了?
这两个Fragment的model肯定是同一个对象,可以用 toString
打印
System.out: com.demo.viewmodel.UserViewModel@d2f5b55
System.out: com.demo.viewmodel.UserViewModel@d2f5b55
确实同一个对象。至于回调 onChanged
,这是观察者模式,这里不赘述了。
前面说了可以感知生命周期,这时候可以把屏幕旋转一下试试,看看值还在不在
用就这么简单
2、分析
(1)observe怎么感知生命周期
(2)怎么回调onChanged的
(1)、感知生命周期
//用的是MutableLiveData 继承了 抽象类 LiveDate
public class MutableLiveData extends LiveData
public abstract class LiveData {
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
owner.getLifecycle().addObserver(wrapper);
}
}
删了一些判断的代码
这代码很少,new了 LifecycleBoundObserver
对象塞入了owner
也就是 activity对象,observer
也就是观察者对象,里面是onChanged
然后把这个wrapper
,put到了mObservers
中
这个mObservers是SafeIterableMap
,看上去是个Map其实是 用Map的Key-Value,封装成了一个LinkedList
最后把wrapper对象,传到了activity里面,其实这里就已经将两者进行了绑定
再稍微深入一点点
//FragmentActivity
public class FragmentActivity extends ComponentActivity implements
ActivityCompat.OnRequestPermissionsResultCallback,
ActivityCompat.RequestPermissionsRequestCodeValidator {
//new了一个对象
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
}
owner.getLifecycle().addObserver(wrapper);
//订阅的observer 会在这里被添加
//LifecycleRegistry
public class LifecycleRegistry extends Lifecycle {
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
//这里对 observer 进行了一些包装
//塞入一个mObserverMap对象中
//这个对象是FastSafeIterableMap本质也是一个Key-Value的LinkList
while(){
//循环分发 事件
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
}
}
}
所以当 model.name.observe(requireActivity(),object:Observer
订阅的时候执行了LifecycleRegistry
的addObserver
方法,包装对象,塞入链表。
ok这时,在ComponentActivity
中 mLifecycleRegistry
对象 管理所有的订阅。
现在已经绑定好了,然后感知生命周期,生命周期无非就onCreate...onDestroy。
前面也说了为防止空指针,直接看onDestroy()
protected void onDestroy() {
super.onDestroy();
mFragments.dispatchDestroy();
//里面 修改了状态、同步状态
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
//不仅仅是destory做了处理
protected void onPause() {
super.onPause();
mResumed = false;
mFragments.dispatchPause();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
markFragmentsCreated();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
}
总结一下
observe和activity绑定,放入了activity链表中,这个链表由activity管理,根据activity的生命周期,修改里面的状态
(2)、回调onChanged
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
owner.getLifecycle().addObserver(wrapper);
//刚才说了订阅会调用addObserver(..)
//这里的observer 就是LifecycleBoundObserver对象
public void addObserver(@NonNull LifecycleObserver observer) {
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
while(){
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
}
}
statefulObserver.dispatchEvent 调用了
-> mLifecycleObserver.onStateChanged(owner, event);
->LifecycleBoundObserver的onStateChanged() 这里已经是LiveData了
->activeStateChanged
->最终dispatchingValue(@Nullable ObserverWrapper initiator) 分发
这个链比较长,可以点击源码走一圈
dispatchingValue(ObserverWrapper initiator)
这里面就是正真的观察者了,
for循环去走onChanged()
方法
3、粘性事件
EventBus的粘性事件,在ActivityA发射了粘性时间,打开ActivityB之后会执行粘性事件
在这里也是一样的道理。
根据刚才的源码,订阅后会进行一次分发,为什么订阅后就会分发?这要根据Google对这个组件的“定义”了
我理解的“定义”是 存活的数据 LiveData ,也就是在Activity、Fragment生命周期内被分发,也就是说Activity、Fragment活着,这数据也得活着。
所以当你屏幕旋转Activity被销毁,又初始化了,这些数据还要再次显示出来,所以产生了粘性事件。
从分发开始看
name.value = str
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
//分发
void dispatchingValue(@Nullable ObserverWrapper initiator) {
do {
if (initiator != null) {
} else {
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
}
//观察者for循环去通知
private void considerNotify(ObserverWrapper observer) {
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
这里会发现有个版本号
在 ObserverWrapper
中 mLastVersion 默认-1
在 LiveData 初始化之后 mVersion 为 0 , 每次 赋值后 mVersion++
发送数据后 会 mLastVersion = mVersion
再根据 if判断 observer.mLastVersion >= mVersion 如果为false就会调用 onChanged
方法。
所以粘性事件有次而来。
这看上去像是个Bug,追本溯源,这个组件的目的,并不是总线消息通信。而是“存活的数据”,当Activity、Fragment,旋转,销毁重建时会及时得到最后一次数据。
学艺不精,如果内容有错误请及时联系我,我及时改正