KunMinX / UnPeek-LiveData

LiveData 数据倒灌:别问,问就是不可预期 - Perfect alternative to SingleLiveEvent, supporting multiple observers.
1.2k stars 120 forks source link

ProtectedUnPeekLiveDataV5疑问 #18

Closed Lumberjack100 closed 3 years ago

Lumberjack100 commented 3 years ago

你好,我在阅读源码试着理解版本代码演进的逻辑,但是我发现 V5版本还是存在HashMap恒久存在,注册的 Observer 越多,占用的内存越大问题 image image image

发现在退出页面调用removeObserver 方法时,入参 observer 进行 Hash 运算得到的 observeKey 与注册 Observer 时得到的observeKey 不一样

RebornWolfman commented 3 years ago

第一 : 入参 observer 进行 Hash 运算得到的 observeKey 与注册 Observer 时得到的observeKey 不一样,这个检测一下是同一个observer 对象。 第二:observeForever() 是需要自己手动注册和删除的,observe 会在activity destory的时候会回调删除;

第三:感觉这样写有点太复杂,本来倒灌的原因就是新监听的oberver的版本是从-1 开始计算;可以自己维护一个版本号,根本就不需要存什么observer

KunMinX commented 3 years ago

@themaster-gh

1.上述你的描述 未提供诊断的数据 且存在歧义,缺乏一致的前提来核对和确认,

2.我自行通过 Log 测试一番,无法复现你说的 Observe 无法 remove 的问题,V5 版的源码设计者在 removeObserver 中,通过 ObserveKey 试图获取的是 ForeverObserver,而非 Observer,当 foreverObserver 不存在时,便默认去 remove observer。

3.V5 源码的设计确实比较复杂,请以最新源码为准。

KunMinX commented 3 years ago

以下是 V6.1 简版代码


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

  private final ConcurrentHashMap<Observer<? super T>, ObserverProxy> observerMap = new ConcurrentHashMap();

  @Override
  public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    Observer<? super T> observer1 = getObserverProxy(observer);
    if (observer1 != null) {
      super.observe(owner, observer1);
    }
  }

  @Override
  public void observeForever(@NonNull Observer<? super T> observer) {
    Observer<? super T> observer1 = getObserverProxy(observer);
    if (observer1 != null) {
      super.observeForever(observer1);
    }
  }

  private Observer<? super T> getObserverProxy(Observer<? super T> observer) {
    if (observerMap.containsKey(observer)) {
      return null;
    } else {
      ObserverProxy proxy = new ObserverProxy(observer);
      observerMap.put(observer, proxy);
      return proxy;
    }
  }

  private class ObserverProxy implements Observer<T> {

    public final Observer<? super T> target;

    public boolean allow;

    public ObserverProxy(Observer<? super T> target) {
      this.target = target;
    }

    @Override
    public void onChanged(T t) {
      if (allow) {
        allow = false;
        target.onChanged(t);
      }
    }
  }

  @Override
  protected void setValue(T value) {
    for (Map.Entry<Observer<? super T>, ObserverProxy> entry : observerMap.entrySet()) {
      entry.getValue().allow = true;
    }
    super.setValue(value);
  }

  @Override
  public void removeObserver(@NonNull Observer<? super T> observer) {
    observerMap.remove(observer);
    super.removeObserver(observer);
  }
}