LiveData源码解析

2021-10-28  本文已影响0人  GIndoc

是什么

是一个可观察的数据存储类,且具备宿主生命周期的感知能力。

优势

各类之间的关系

image.png

注册观察者流程,事件分发原理

// LiveData.class
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 判断是否主线程
        assertMainThread("observe");
        
        // 如果宿主已经destroy,则return
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        
        // 用LifecycleBoundObserver包装observer,其中包含LifecycleOwner,且能响应生命周期事, 如果页面destroy了,可以将observer自动从lifecycle移除
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        
        // 将observer和wrapper保存起来,如果之前已经存在则返回之前的wrapper,否则返回null
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        
        // 如果之前已经添加过该observer,且observer不是绑定当前owner,抛出异常
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        // 如果之前已经添加过该observer,则不再添加,return
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }
    
// 更新mActiveCount,判断是否触发LiveData的onActive()和onInactive()
@MainThread
void changeActiveCounter(int change) {
        int previousActiveCount = mActiveCount;
        mActiveCount += change;
        if (mChangingActiveState) {
            return;
        }
        mChangingActiveState = true;
        try {
            // 更新mActiveCount
            while (previousActiveCount != mActiveCount) {
                boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
                boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
                previousActiveCount = mActiveCount;
                
                // 触发onActive()或onInactive()
                // 可以充分利用 onActive() 方法被激活的时机,来实现一些数据懒加载的功能。
                if (needToCallActive) {
                    onActive();
                } else if (needToCallInactive) {
                    onInactive();
                }
            }
        } finally {
            mChangingActiveState = false;
        }
}

// 给Observer分发数据
void dispatchingValue(@Nullable ObserverWrapper initiator) {
        // 如果正在分发数据,则将mDispatchInvalidated置为true,后面分发结束后会再分发一次
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // 如果initiator则只给initiator分发,否则给所有observer分发数据
            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());
                    // 如果正在分发数据,dispatchingValue(observer)又被调用了,则停止本次分发,重新开始分发
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
}

// 真正分发数据的地方
private void considerNotify(ObserverWrapper observer) {
        // 如果observer所在页面不是活跃状态,则不分发数据
        if (!observer.mActive) {
            return;
        }
        
        // 获取observer所在页面的最新状态,有可能页面状态变了,但是还没更新Observer的mActive
        // 我们仍然先判断observer.mActive,如果页面已经变为活跃状态,但是observer.mActive还没更新,即还是不活跃状态,则更新observer.mActive,但仍不分发数据
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        
        // observer的数据版本大于LiveData的版本,即接收数据的次数大于发送数据的次数,说明observer已经收到最新的数据,不再回调observer#onChanged()通知更新
        // observer的mLastVersion=-1,如果之前已经发送过数据了,即mLastVersion<mVersion,则会出现黏性事件,后注册的观察者收到了前面发送的消息
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        
        // 每分发一次消息,则把观察者和LiveData的version对齐,防止重复发送
        observer.mLastVersion = mVersion;

        // 通知更新
        observer.mObserver.onChanged((T) mData);
}
    
    
#########################################################


// LifecycleBoundObserver.class
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        // 当前界面是否活跃,即当前界面状态是否大于STARED
        @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();
            
            // 如果当前界面已经销毁,则移除observer
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // 给父类OvserverWrapper设置活跃状态,如果是活跃的话分发数据
            activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

// ObserverWrapper.class
    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;
            }
            
            mActive = newActive;
            // 更新mActiveCount,判断是否出发LiveData的onActive()和onInactive()
            changeActiveCounter(mActive ? 1 : -1);
            
            // 如果是活跃的话,分发数据
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }
image.png

小结

  1. 首先调用LiveData#observe(owner, observer)进行注册,这时会将observer包装成LifecycleBoundObserver
  2. LifecycleBoundObserver继承自ObserverWrapper,保存了Observer和LifecycleOwner,所以可以回调observer#onChanged(data),也可以从LifecycleOwner中获得页面活跃状态;同时它实现了LifecycleEventObserver,所以能够监听lifecycle的生命周期事件,在页面销毁时移除observer,在页面变为活跃状态时,接收最新的数据(如果之前没有接收过的话)。
  3. 如果是在页面onResume是注册的观察者,onStateChanged(owner, event)会回调3次:onCreate、onStart、onResume。但是observer#onChanged(data)只会回调一次,因为onStateChanged(owner, event)会判断如果页面状态和之前一样(mActive没有改变),则return。
  4. 另外即使mActive改变了,但是如果数据没有改变,也不会回调observer#onChanged(data),因为LiveData会根据ObserverWrapper#mLastVersion和自身的mVersion判断数据的接收次数和发送次数是否一致:mLastVersion<mVersion则发送;否则不发送。
  5. LifecycleBoundObserver#onStateChanged(owner, event)回调时,会根据是否有活跃的观察者(mActiveCount)来触发LiveData#onActive()/onInactive()
  6. 之后就会判断页面是否活跃,如果活跃则分发数据,调用considerNotify方法,通过ObserverWrapper#mLastVersion和LiveData#mVersion来判断是否触发Observer#onChanged(data)

发送数据

// LiveData.class

private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            // 加锁,防止主线程更新数据时,mPendingData被改变
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
};
    
    
protected void postValue(T value) {
        boolean postTask;
        // 加锁,防止主线程更新数据时,mPendingData被改变
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        // 如果postTask=false,说明正在等待runnable获取mPendingData更新界面,不再发送runnable
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

@MainThread
protected void setValue(T value) {
        assertMainThread("setValue");
        // 增加发送次数
        mVersion++;
        mData = value;
        // 通知所有的observer更新数据
        dispatchingValue(null);
}
image.png

数据倒灌是什么

页面在再次打开时,收到了旧数据。
比如,有3个fragment:列表、详情、编辑,它们都共享viewmodel中的同一个liveData,在编辑页编辑完后通过livedata保存数据,退出返回详情页时,详情页恢复活跃状态,会从liveData收到最新的数据更新界面。再次回退到列表页,点击另一个item打开详情页,这时详情页调用liveData#addObserver()会从liveData收到之前到旧数据,这就是数据倒灌。

如果解决黏性事件

  1. 反射干涉Version
    不推荐这种方式,网上的方案是在LiveData#observe()方法中利用反射修改LifecycleBoundObserver中的mLastVersion的值=LiveData的mVersion,但是这种方案只适合在页面的onCreate(页面还不是活跃状态)时注册observer,因为这时页面的state是INITIALIZED,LiveData#observe()->LifecycleRegistrty#addObserver()中由于LifecycleRegistrty.mState=LifecycleBoundObserver.mState,导致不会回调ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged(),从而不会触发observer.onChanged(),也就达到了取消粘性事件的目的。但是如果在onStart()或之后(页面变为活跃状态)注册observer,由于这时页面的state是大于INITIALIZED的, 所以在LiveData#observe()->LifecycleRegistrty#addObserver()中会触发ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged(),也就导致observer.onChanged()被触发,还是发生粘性事件。

  2. 自定义LiveData和Observer,分别在内部维护一个version。当不需要粘性事件时,在用LiveData注册Observer时,将LiveData的version赋值给observer的version;当需要粘性事件时,在用LiveData注册Observer时,设置Observer的version为-1。

参考:https://github.com/KunMinX/UnPeek-LiveData/blob/de958b679b/unpeeklivedata/src/main/java/com/kunminx/architecture/ui/callback/ProtectedUnPeekLiveData.java#L40-L176

public class ProtectedUnPeekLiveData<T> extends LiveData<T> {


  private final static int START_VERSION = -1;


  private final AtomicInteger mCurrentVersion = new AtomicInteger(START_VERSION);


  protected boolean isAllowNullValue;


  /**
   * TODO tip:当 liveData 用作 event 用途时,可使用该方法来观察 "生命周期敏感" 的非粘性消息
   * <p>
   * state 是可变且私用的,event 是只读且公用的,
   * state 的倒灌是应景的,event 倒灌是不符预期的,
   * <p>
   * 如果这样说还不理解,详见《LiveData 唯一可信源 读写分离设计》的解析:
   * https://xiaozhuanlan.com/topic/2049857631
   *
   * @param owner    activity 传入 this,fragment 建议传入 getViewLifecycleOwner
   * @param observer observer
   */
  @Override
  public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    super.observe(owner, createObserverWrapper(observer, mCurrentVersion.get()));
  }


  /**
   * TODO tip:当 liveData 用作 event 用途时,可使用该方法来观察 "生命周期不敏感" 的非粘性消息
   *
   * @param observer observer
   */
  @Override
  public void observeForever(@NonNull Observer<? super T> observer) {
    super.observeForever(createObserverWrapper(observer, mCurrentVersion.get()));
  }


  /**
   * TODO tip:当 liveData 用作 state 用途时,可使用该方法来观察 "生命周期敏感" 的粘性消息
   *
   * @param owner    activity 传入 this,fragment 建议传入 getViewLifecycleOwner
   * @param observer observer
   */
  public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    super.observe(owner, createObserverWrapper(observer, START_VERSION));
  }


  /**
   * TODO tip:当 liveData 用作 state 用途时,可使用该方法来观察 "生命周期不敏感" 的粘性消息
   *
   * @param observer observer
   */
  public void observeStickyForever(@NonNull Observer<? super T> observer) {
    super.observeForever(createObserverWrapper(observer, START_VERSION));
  }


  /**
   * TODO tip:只需重写 setValue
   * postValue 最终还是会经过这里
   *
   * @param value value
   */
  @Override
  protected void setValue(T value) {
    mCurrentVersion.getAndIncrement();
    super.setValue(value);
  }


  /**
   * TODO tip:
   * 1.添加一个包装类,自己维护一个版本号判断,用于无需 map 的帮助也能逐一判断消费情况
   * 2.重写 equals 方法和 hashCode,在用于手动 removeObserver 时,忽略版本号的变化引起的变化
   */
  class ObserverWrapper implements Observer<T> {
    private final Observer<? super T> mObserver;
    private int mVersion = START_VERSION;


    public ObserverWrapper(@NonNull Observer<? super T> observer, int version) {
      this.mObserver = observer;
      this.mVersion = version;
    }


    @Override
    public void onChanged(T t) {
      if (mCurrentVersion.get() > mVersion && (t != null || isAllowNullValue)) {
        mObserver.onChanged(t);
      }
    }


    @SuppressWarnings("unchecked")
    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      ObserverWrapper that = (ObserverWrapper) o;
      return Objects.equals(mObserver, that.mObserver);
    }


    @Override
    public int hashCode() {
      return Objects.hash(mObserver);
    }
  }


  /**
   * TODO tip:
   * 通过 ObserveForever 的 Observe,需要记得 remove,不然存在 LiveData 内存泄漏的隐患,
   * 保险的做法是,在页面的 onDestroy 环节安排 removeObserver 代码,
   * 具体可参见 app module 中 ObserveForeverFragment 的案例
   *
   * @param observer observeForever 注册的 observer,或 observe 注册的 observerWrapper
   */
  @Override
  public void removeObserver(@NonNull Observer<? super T> observer) {
    if (observer.getClass().isAssignableFrom(ObserverWrapper.class)) {
      super.removeObserver(observer);
    } else {
      super.removeObserver(createObserverWrapper(observer, START_VERSION));
    }
  }


  private ObserverWrapper createObserverWrapper(@NonNull Observer<? super T> observer, int version) {
    return new ObserverWrapper(observer, version);
  }


  /**
   * TODO tip:
   * 手动将消息从内存中清空,
   * 以免无用消息随着 SharedViewModel 的长时间驻留而导致内存溢出的发生。
   */
  public void clear() {
    super.setValue(null);
  }


}
上一篇 下一篇

猜你喜欢

热点阅读