面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制
Posted 初一十五啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制相关的知识,希望对你有一定的参考价值。
💡前言
相信很多人在职业生涯的面试过程中都会被问到关于LiveData
相关的。
今天就来分析一下LiveData
的粘性事件以及LiveData
订阅与数据分发。
另外总结一下LiveDate
事件事件一共有以下内容:
LiveDate
粘性事件Framework
源码分析
Jetpack
中的状态机是如何管理生命周期
Hook
实现LiveDate
非粘性功能
LiveDate
递归调用源码是如何做容错的
企业级LiveDateBus
封装实现
💡 一丶livedata
粘性事件
粘性事件:相对比普通事件,粘性事件支持先发送事件,再去注册订阅者。一旦完成订阅动作,这个订阅者就会接收到该粘性事件。
所以粘性其实就可以理解为观察者模式的升级,让观察者与被观察者对象之间更加的粘合。
举个栗子,我们利用livedata
来做APP
的全局状态管理
object GlobalState
val jcTestNumberLd: MutableLiveData<Int> = MutableLiveData<Int>()
然后在 Fragment
以及 Activity
中观察该 jcTestNumberLd
。
/** 观察 GlobalState 的 Activity */
class JcTestActivity : BaseVmDbActivity<MainViewModel, ActivityJcTestBinding>()
override fun initView()
viewBinding.incButton.setOnClickListener
GlobalState.jcTestNumberLd.value =
if (GlobalState.jcTestNumberLd.value == null)
1
else
GlobalState.jcTestNumberLd.value!!.toInt().inc()
override fun initObserve()
GlobalState.jcTestNumberLd.observe(this,
Log.e(TAG, "initObserve: jctestNumber = $it")
)
........
/** 观察 GlobalState 的 Fragment */
class EventFragment : BaseVmDbFragment<EventViewModel, FragmentEventBinding>()
override fun setObservers()
GlobalState.jcTestNumberLd.observe(viewLifecycleOwner,
Log.e(TAG, "setObservers: jctestNumber = $it", )
)
........
注意:这里例子中的 EventFragment
并不是关联到 JcTestActivity
的。用户会先进入到 JcTestActivity
,然后由用户控制进入到另一个Activity
中,加载 EventFragment
。
我们来执行一下以下五步操作,来看一下输出的日志。
- 当我们第一次进入
JcTestActivity
时,注册了观察者,没有接收到观察事件,所以也就不会执行观察动作。 - 然后我们点击自增按钮为
jcTestNumberLd
赋予新值,接收到观察事件,执行观察动作,输出 1。 - 再次点击自增按钮,有观察事件,执行观察动作,输出 2。
- 再次点击自增按钮,有观察事件,执行观察动作,输出 3。
- 然后我们到
EventFragment
中,注册新的观察者,发现直接接收到观察事件,执行观察动作,输出 3。
输出结果:
E/JcTestActivity: initObserve: jctestNumber = 1
E/JcTestActivity: initObserve: jctestNumber = 2
E/JcTestActivity: initObserve: jctestNumber = 3
E/EventFragment: setObservers: jctestNumber = 3
这就是粘性事件!所以说,LiveData
是粘性的。
💡二丶LiveData
是怎么实现粘性的呢?
在知道LiveData
是粘性后,我不经问自己:它是怎么实现粘性的呢?
这里我们先来回顾一下EventBus
粘性事件的实现原理。
EventBus
在发送粘性事件时,会将这粘性事件存到一个叫做 stickyEvents
的集合中,然后等注册订阅新的观察者对象时,会去遍历该集合中的粘性事件,如果有找到对应的粘性事件,就将该粘性事件发送给该观察者。(如果你对EventBus
粘性事件不熟悉,可以点击EventBus
源码解析(很细 很长)进一步了解学习。)
LiveData
是不是也是以同样的原理来实现粘性的呢?
public LiveData(T value)
mData = value;
mVersion = START_VERSION + 1;
/**
* Creates a LiveData with no value assigned to it.
*/
public LiveData()
mData = NOT_SET;
mVersion = START_VERSION;
从 LiveData
的构造函数中可以发现有一个 mVersion
参数,它代表着 LiveData
的版本号,每当我们进行 setValue
时,都会让 mVersion
进行自增。
另外,ObserverWrapper
这个观察者包装类中也有一个 int mLastVersion = START_VERSION
版本号。
这两个版本号分别是被观察者对象与观察者对象的版本号,那这二者之间又有什么关系呢?
在判断是否通知观察者的 considerNotify(ObserverWrapper observer)
方法中,会对这两个版本号进行比较。
private void considerNotify(ObserverWrapper observer)
...省略代码...
//如果观察者的版本号 >= LiveData的版本号,就说明该观察者已经接收过该观察事件,也就不再分发。
if (observer.mLastVersion >= mVersion)
return;
//反之,分发观察事件给该观察者,让其执行对应的观察动作,并更新观察者的版本号
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
概括一下:根据比对观察者对象的版本号与LiveData
的版本号来判断是否分发当前版本的数据给该观察者。如果观察者对象的版本号大于等于LiveData
的版本号,也就说明该观察者已经接收过当前版本的数据了,也就不需要再次分发了(等待下一次数据更新)。反之,则分发当前版本的数据给该观察者,让其执行对应的观察动作,并更新观察者的版本号,也就是更新为LiveData
的版本号。
💡三丶Google
为何要将LiveData
设计成粘性的
LiveData 是可观察的数据存储器类,这样也就意味着存储在LiveData中的数据是会更新的,既然是会更新的,那必定就会存在状态,即最新数据状态。
所以,当数据状态发生改变时(数据发生了更新),LiveData需要告诉所有处于活跃状态的观察者, 让其同步更新数据。这应该很好理解了,因为这就是普通事件,先注册观察者,再去更新被观察者对象,触发观察事件。
那这时,你再去新注册一个观察者对象,你认为它需不需要知道此时LiveData最新的数据呢?
答案是:需要。
因为所有的观察者,都只需要知道LiveData
中存储的数据,而且是最新数据。不管我是新注册的观察者,只要你LiveData
有了最新数据,就需要告诉我。而关于有无新数据,从代码上体现出来的就是,LiveData.mVersion > Observer.mLastVersion
。
这也就是粘性事件,先更新被观察者对象,触发观察事件,再去注册观察者,观察者会直接接收到该观察事件,执行对应的观察动作。
它的功能属性导致其只能是粘性的。
💡 四丶LiveData
订阅与数据分发
使用
public class LiveDataActivity extends AppCompatActivity
MutableLiveData liveData= new MutableLiveData<String>();
void liveDataTest()
// 任何线程都可以发送数据
liveData.postValue("postValue");
// 只有主线程可以发送数据
// liveData.setValue("setValue")
void observeTest()
//订阅
liveData.observe(this, new Observer<String>()
@Override
public void onChanged(String data)
//收到数据data
);
//可以有多个订阅
liveData.observe(this, new Observer<String>()
@Override
public void onChanged(String data)
//收到数据data
);
阶段一:
postValue
:
protected void postValue(T value)
boolean postTask;
synchronized (mDataLock)
postTask = mPendingData == NOT_SET;
mPendingData = value;
if (!postTask)
return;
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
- 将用户发送的数据给到一个
mPendingData
的变量; - 切换到主线程
- 执行了一个
mPostValueRunnable;
mPostValueRunnable
:
volatile Object mPendingData = NOT_SET;
private int mVersion;
private final Runnable mPostValueRunnable = new Runnable()
@SuppressWarnings("unchecked")
@Override
public void run()
Object newValue;
synchronized (mDataLock)
newValue = mPendingData;
mPendingData = NOT_SET;
setValue((T) newValue);
;
- 在
mPostValueRunnable
中将mPendingData
给到了新的临时变量newValue; mPendingData
的值置为空;- 调用
setValue(newValue);
setValue
:
private volatile Object mData;
private int mVersion;
@MainThread
protected void setValue(T value)
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
- 将数据版本mVersion +1;
- 将发送的数据给到了mData;
- 调用分发数据
dispatchingValue
看到这里发现,数据其实最后存到了mData
中;若想发送订阅消息,肯定得添加订阅者;
阶段二:
添加订阅者,observe()
:
//用户使用:
//liveData.observe(this@LiveDataActivity,
//
//)
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
assertMainThread("observe");
//如果被观察者的生命周期是DESTROYED,就不添加订阅者
if (owner.getLifecycle().getCurrentState() == DESTROYED)
// ignore
return;
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
...
owner.getLifecycle().addObserver(wrapper);
- 将有生命周期的
Activity
和订阅者Observer
传了进来; - 判断
Activity
的生命周期; - 将
Activity
和Observer
封装为一个LifecycleBoundObserver
对象; - 将
LifecycleBoundObserver
放到了mObservers
这个Map集合中; map
的key
为观察者,value
为封装了activity
和观察者Observer
的对象LifecycleBoundObserver;
LifecycleBoundObserver
及它的父类ObserverWrapper
:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer)
super(observer);
mOwner = owner;
...
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event)
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED)
removeObserver(mObserver);
return;
Lifecycle.State prevState = null;
while (prevState != currentState)
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
...
@Override
void detachObserver()
mOwner.getLifecycle().removeObserver(this);
//ObserverWrapper
private abstract class ObserverWrapper
//传进来的观察者放这里了
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer)
mObserver = observer;
...
void activeStateChanged(boolean newActive)
if (newActive == mActive)
return;
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive)
dispatchingValue(this);
- 将有生命周期的
Activity
给到了LifecycleBoundObserver
的mOwner
; - 将观察者给到了
LifecycleBoundObserver
的父类ObserverWrapper
的mObserver
; - 其实
LifecycleBoundObserver
就可以获取到Activity
和mObserver
; - 上一步,看到将封装后的
LifecycleBoundObserver
放到了mObservers
这个map
中; map
的key
为观察者,value
为封装了activity
和观察者Observer
的对象LifecycleBoundObserver
;
阶段三:
分发:
在阶段一setValue()
时,调用了dispatchingValue(null);
void dispatchingValue(@Nullable ObserverWrapper initiator)
if (mDispatchingValue)
mDispatchInvalidated = true;
return;
mDispatchingValue = true;
do
mDispatchInvalidated = false;
if (initiator != null)
considerNotify(initiator);
initiator = null;
else
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); )
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated)
break;
while (mDispatchInvalidated);
mDispatchingValue = false;
private void considerNotify(ObserverWrapper observer)
if (!observer.mActive)
return;
...
if (observer.mLastVersion >= mVersion)
return;
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
- 当为
null
时,走到了for
循环 - 循环取出
map
中的value
,而value
就是LifecycleBoundObserver;
LifecycleBoundObserver
中有mObserver
,mObserver
就是用户传的观察者;mObserver.onChanged((T) mData);
- 完成了“主动”分发;
💡到此LiveDate
关于粘性事件与订阅和数据分发就讲完啦。
更多Android面试大全总结(全文30W+字.200多个知识点.330张图.38个视频合集)
包含(视频+文字):
android
基础-性能优化-Framework
-compose
开源项目-音视频初中高-架构-车载-Flutter
-Kotlin
-Harmony OS
+音视频详细文档。
以上是关于面试官:我看你简历上有写 LiveData,那谈谈LiveData事件机制的主要内容,如果未能解决你的问题,请参考以下文章