LiveData粘性事件的问题2
之前在LiveData文章中已经分析过粘性事件的原因了,但是在实际使用中还是遇到了一些问题,
网上的UnstickyLiveData的写法通常是反射修改LiveData.ObserverWrapper.mLastVersion,
@Override public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); super.observe(owner, observer); HookUtils.alignVersion(this, observer); }
public static void alignVersion(LiveData liveData, Observer observer) { Class<LiveData> liveDataClass = LiveData.class; try { //获取field private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers Field mObservers = liveDataClass.getDeclaredField("mObservers"); mObservers.setAccessible(true); //获取SafeIterableMap集合mObservers Object observers = mObservers.get(liveData); //获取SafeIterableMap的get(Object obj)方法 Class<?> observersClass = observers.getClass(); Method methodGet = observersClass.getDeclaredMethod("get", Object.class); methodGet.setAccessible(true); //获取到observer在集合中对应的ObserverWrapper对象 Object objectWrapperEntry = methodGet.invoke(observers, observer); Object objectWrapper = null; if (objectWrapperEntry instanceof Map.Entry) { objectWrapper = ((Map.Entry) objectWrapperEntry).getValue(); } if (objectWrapper == null) { throw new NullPointerException("ObserverWrapper can not be null"); } //获取ObserverWrapper的Class对象 LifecycleBoundObserver extends ObserverWrapper Class<?> wrapperClass = objectWrapper.getClass().getSuperclass(); //获取ObserverWrapper的field mLastVersion Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion"); mLastVersion.setAccessible(true); //把当前ListData的mVersion赋值给 ObserverWrapper的field mLastVersion mLastVersion.set(objectWrapper, liveData.getVersion()); } catch (Exception e) { if (BuildConfig.DEBUG) { throw new RuntimeException(e); } else { e.printStackTrace(); } } }
但是有个问题,如果在生命周期当前是:
owner.getLifecycle().getCurrentState().isAtLeast(STARTED)
那么里边会立马调用observer.onChange,这显然是有问题的,正确的做法应该是我下边的代码
@Override public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (getVersion() > LiveData.START_VERSION) {//有新值,会调用onChanged if (owner.getLifecycle().getCurrentState().isAtLeast(STARTED)) {//此时super.observe内会立马调用onChanged PreventStickyEventObserverWrapper<? super T> myObserverWrapper = myObserverWrapperMap.get(observer); if (myObserverWrapper == null) { myObserverWrapper = new PreventStickyEventObserverWrapper<>(observer); myObserverWrapper.preventStickyEvent = true; myObserverWrapperMap.put(observer, myObserverWrapper); super.observe(owner, myObserverWrapper); } } else { super.observe(owner, observer); HookUtils.alignVersion(this, observer); } } else { super.observe(owner, observer); } }
class PreventStickyEventObserverWrapper<T> implements Observer<T> { @NonNull final Observer<T> observer; boolean preventStickyEvent = false; PreventStickyEventObserverWrapper(@NonNull Observer<T> observer) { this.observer = observer; } @Override public void onChanged(@Nullable T t) { if (preventStickyEvent) { preventStickyEvent = false; return; } observer.onChanged(t); } }
这样就覆盖了各种情况。
LiveDataBus
事件总线是一种解耦的编程方式,特别是在页面深度特别深,需要通知之前的某个页面状态时非常有用,
主流的主要是EventBus,RxBus,但这些都有个问题就是生命周期感知的问题,
而LiveData之所以好,就是因为只在页面真正显示的时候才去通知观察者,所以仿照着前者写了个LiveDataBus,实现起来也很简单,看起来也很方便,没有其他的杂七杂八的逻辑。