Android Jetpack
提供了一系列的庫和工具,其中就包括了LiveData
。今天我要講的是當MutableLiveData
作爲全局變量,觀察者方法被重複調用的問題。
DataRepository
作爲單例類,聲明類型MutableLiveData
的變量data。
object DataRepository {
var data = MutableLiveData<String>()
}
在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<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;
}
// 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<T> extends MutableLiveData<T> {
@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<LiveData> 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();
}
}
}
文章相關鏈接