Android Jetpack
提供了一系列的库和工具,其中就包括了LiveData
。今天我要讲的是当MutableLiveData
作为全局变量,观察者方法被重复调用的问题。
DataRepository
作为单例类,声明类型MutableLiveData
的变量data。
object DataRepository {
var data = MutableLiveData()
}
在DataActivity
的onCreate
方法中,添加变量data方法的观察者,紧接着使用postValue
方法对data
进行赋值。
class DataActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_data)
DataRepository.data.observe(this, Observer {
Log.i("TAG", "data:$it")
})
Handler().postDelayed({
DataRepository.data.postValue("${Random.nextInt(100)}")
}, 1 * 1000)
}
}
主要代码就是以上内容,代码十分简单,看起来也没有什么问题。假设打开APP
,首先进入MainActivity
页面,再由MainActivity
跳转到DataActivity
。在进入DataActivity
后,将会打印data:$it
,一切都很正常。当从DataActivity
返回到MainActivity
,再次进入到DataActivity
,会发现data:$it
会打印两次。
2020-05-27 10:21:15.626 I/DataActivity: data:15
2020-05-27 10:21:16.622 I/DataActivity: data:17
这样的结果就十分的奇怪了,为什么第一次进入DataActivity
,输出正常,第二次进入DataActivity
,却打印了两次?我们可以看到这两次的结果是不同的,并且存在1秒钟的间隔,那就可以猜测观察者方法并不是被一次data的赋值调用了两次,而是进入到DataActivity
,注册观察者后,其方法就被调用了。下面我们来LiveData
的observe
。
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);
}
如上面的代码所示,生成了LifecycleBoundObserver
对象,并将此对象添加为owner
生命周期的观察者。
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
}
void activeStateChanged(boolean newActive) {
......
if (mActive) {
dispatchingValue(this);
}
}
当生命周期发生改变时,执行完就会先调用onStateChanged
,之后调用activeStateChanged
方法。当生命周期大于等于STARTED
时,就会调用dispatchingValue
方法
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, 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;
}
// 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);
}
接着就会调用considerNotify
,将数据通知到观察者。其实第二次进入DataActivity
,是由于第一次postValue
添加的值已经赋值给mData
,当第二次进入DataActivity
后,执行到生命周期STARTED
后,就会把第一次缓存的mData
再次通知出来。出现这个问题的原因已经找到了,那么怎么解决这个问题呢。我们可以看下当observer.mLastVersion >= mVersion
就不会通知观察者。每次改变LiveData
时,mVersion
的值就会加1,当通知给观察者后,就会把值赋值给观察者的mLastVersion
,避免的重复通知。由于LiveData
的mVersion
在第一次设置了值,所以两者的版本不一致。解决问题思路是在调用observe
后,使用反射,将LiveData
的mVersion
赋值给observer.mLastVersion
,这样两者版本一样,onChanged
方法就不会执行。
public class PublicMutableLiveData extends MutableLiveData {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
super.observe(owner, observer);
hook(observer);
}
private void hook(Observer super T> observer) {
Class liveDataClass = LiveData.class;
try {
Field mObservers = liveDataClass.getDeclaredField("mObservers");
mObservers.setAccessible(true);
Object mObserversObject = mObservers.get(this);
if(mObserversObject == null){
return;
}
Class> mObserversClass = mObserversObject.getClass();
Method methodGet = mObserversClass.getDeclaredMethod("get", Object.class);
methodGet.setAccessible(true);
Object entry = methodGet.invoke(mObserversObject, observer);
if(!(entry instanceof Map.Entry)){
return;
}
Object lifecycleBoundObserver = ((Map.Entry) entry).getValue();
Class> observerWrapper = lifecycleBoundObserver.getClass().getSuperclass();
if(observerWrapper == null){
return;
}
Field mLastVersionField = observerWrapper.getDeclaredField("mLastVersion");
mLastVersionField.setAccessible(true);
Method versionMethod = liveDataClass.getDeclaredMethod("getVersion");
versionMethod.setAccessible(true);
Object version = versionMethod.invoke(this);
mLastVersionField.set(lifecycleBoundObserver, version);
mObservers.setAccessible(false);
methodGet.setAccessible(false);
mLastVersionField.setAccessible(false);
versionMethod.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
文章相关链接