Jetpack系列:
Lifecycle使用方法、原理分析 - 掘金 (juejin.cn)
LiveData使用方法、原理分析 - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(一) - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(二) - 掘金 (juejin.cn)
自定义View中获取ViewModel - 掘金 (juejin.cn)
LiveData 使用方法、原理分析
1.常规使用方法
/**
* liveData 将setValue()&postValue() 设置protected 对外不暴露
* MutableLiveData 继承LiveData,对外公开setValue()&postValue(),初始化对外暴露LiveData类型
*
**/
private val _data:MutableLiveData<String> = MutableLiveData("A")
val data:LiveData<String> = _data
viewModel.data.observe(this) { it ->
Log.d("CustomViewActivity", "=======it:$it")
}
viewModel.data.observeForever {it->
Log.d("CustomViewActivity", "=======it:$it")
}
2.LiveData原理分析
LiveData源码中只有3个类,LiveData(抽象类)、MutableLiveData(实现类)、Observer(接口类、回调)
Observer.java
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
}
在LiveData中内部类ObserverWrapper
- 重点activeStateChanged(),状态发生改变时分发数据(只有在激活状态下);
- changeActiveCounter()会记录当前liveData所持有observer数量,会回调active()&inactive()
- 有两个实现类 AlwaysActiveObserver、LifecycleBoundObserver,分别对应observeForever、obverve;
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
}
/***
* observeForever() 设置监听Observer对象
***/
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
/***
* 实现LifecycleEventObserver接口,根据 LifecycleObserver 生命周期变化判断是否分发数据
* LiveData精华所在,根据生命周期变化更新数据
***/
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@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
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
对Observer进行封装, owner.getLifecycle().addObserver(wrapper)对生命周期进行监听; 而observeForever wrapper.activeStateChanged(true)设置一直处于激活状态,不跟随生命周期变化
@MainThread
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);
}
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
3.setValue() & postValue()区分
postValue()通过线程将数据发送,会存在发送数据丢失等问题,实际执行切换线程操作,在连续多次调用后,mPendingData会被赋予最新值,在mPostValueRunnable中会将最新的mPendingData设置为最后一次值**
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
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;
}
关于网络流传LiveData “粘性”问题
首先需要弄清楚一个问题,UI界面接收的数据、事件区分来分析,数据粘性用于UI显示本身是没有问题的,LiveData本身设计初衷解决UI界面显示,比如:用户登录成功后显示头像+用户名等相关信息,在不同界面通过LiveData传递数据就是合理的
再继续用登录场景进行模拟,如果在用户名、密码输入错误时进行Toast提示,如果此时用LiveData传递这个登录失败提示时就会出现再每次回到这个界面时,或者屏幕旋转导致Activity生命周期重新执行时,就会出现多次Toast提示,不符合业务场景需求,可以理解会为事件,MVI架构设计思路大致也是如此
反射方案修改LiveData.observer()中的Observer的mLastVersion解决:
class NoStickMutableLiveData<T> constructor(private var isStick:Boolean = false): MutableLiveData<T>(){
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
if (!isStick){
hook(observer)
}
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
if (!isStick){
hook(observer)
}
}
private fun hook(observer: Observer<in T>){
val liveDataClass = LiveData::class.java
val mObserverFiled = liveDataClass.getDeclaredField("mObservers")
mObserverFiled.isAccessible = true
val mObserversMap:Any = mObserverFiled.get(this)
val mObserversMapClass = mObserversMap.javaClass
val mObserversMapGet = mObserversMapClass.getDeclaredMethod("get",Any::class.java)
mObserversMapGet.isAccessible=true
var observerWrapper:Any?
val invokeEntry = mObserversMapGet.invoke(mObserversMap, observer)
if (invokeEntry != null && invokeEntry is Map.Entry<*, *>){
observerWrapper = invokeEntry.value
}else{
throw Exception("observerWrapper error")
}
val observerWrapperSuperClass = observerWrapper?.javaClass?.superclass
val mLastVersionField = observerWrapperSuperClass?.getDeclaredField("mLastVersion")
mLastVersionField?.isAccessible = true
val mLastVersion = mLastVersionField?.get(observerWrapper)
Log.d("NoStickMutableLiveData", "mLastVersion:$mLastVersion")
val mVersionFiled = liveDataClass.getDeclaredField("mVersion")
mVersionFiled.isAccessible=true
val mVersion = mVersionFiled.get(this)
Log.d("NoStickMutableLiveData", "mVersion:$mVersion")
mLastVersionField?.set(observerWrapper, mVersion)
}
}
关于LiveData粘性事件所带来问题的解决方案 - 简书 (jianshu.com)
不做跟风党,LiveData,StateFlow,SharedFlow 使用场景对比 - 掘金 (juejin.cn)