美文网首页
LiveData 你应该知道的知识点

LiveData 你应该知道的知识点

作者: Drew_MyINTYRE | 来源:发表于2022-04-05 19:55 被阅读0次

LiveData 如何避免内存泄漏?

当一个长生命周期的对象引用了一个短生命周期的对象,就会产生内存泄漏。

比如当我们使用 Rxjava 来发起一个网络请求的时候,在 Activity 关闭的时候没有取消订阅,就会发生内存泄漏。

使用 LiveData 却不用担心这个问题,LiveData 订阅后,在页面销毁后可以自动取消订阅。

class MutableLiveDataFragment : Fragment() {

    private val changeObserver = Observer<String> { value ->
        value?.let { txt_fragment.text = it }
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        getLiveDataA().observe(this, changeObserver)
    }
}

LiveData 存在的问题?

在使用 LiveData 的过程中,订阅者会收到订阅之前发布的消息。对于一个消息总线来说,这是不可接受的。无论 EventBus 或者 RxBus,订阅方都不会收到订阅之前发出的消息。为什么会存在这个问题呢?

LifeCircleOwner 的状态发生变化的时候,会调用LiveData.ObserverWrapperactiveStateChanged 函数,如果这个时候 ObserverWrapper 的状态是 active,就会调用 LiveDatadispatchingValue

@MainThread
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);
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull
    final LifecycleOwner mOwner;

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

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }

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

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}
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;
        }
        // immediately set active state, so we'd never dispatch anything to inactive
        // owner
        mActive = newActive;
        changeActiveCounter(mActive ? 1 : -1);
        if (mActive) {
            dispatchingValue(this);
        }
    }
}
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;
}

LiveDataconsiderNotify() 方法中,如果 ObserverWrappermLastVersion 小于 LiveDatamVersion,就会去回调 mObserveronChanged() 方法。而每个新的订阅者,其 version 都是 -1,LiveData 一旦设置过其 version 是大于 -1 的(每次 LiveData 设置值都会使其 version加1),这样就会导致 LiveDataBus 每注册一个新的订阅者,这个订阅者立刻会收到一个回调,即使这个设置的动作发生在订阅之前。

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // 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);
}

看过上面的源码,我们总结一下发生的核心原因。

对于 LiveData,其初始的 version 是 -1,当我们调用了其 setValue 或者postValue,其 version 会 +1;对于每一个观察者的封装 ObserverWrapper,其初始 version 也为 -1,也就是说,每一个新注册的观察者,其 version 为-1;当 LiveData 设置这个 ObserverWrapper 的时候,如果 LiveData 的 version 大于 ObserverWrapper 的 version,LiveData 就会强制把当前 value 推送给该 Observer

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}    

如何解决 刚订阅就收到之前发送的值 这个问题呢?

明白了问题产生的原因之后,我们来看看怎么才能解决这个问题。很显然,根据之前的分析,只需要在注册一个新的订阅者的时候把 ObserverWrapper 的 version 设置成跟 LiveData 的 version 一致即可。

解决问题的思路是:

无论 ObserverWrapper 还是 LifecycleBoundObserver 都是私有的或者包可见的,所以无法通过继承的方式更改 LifecycleBoundObserver 的 version。

那么能不能从 Map 容器 mObservers 中取到 LifecycleBoundObserver,然后再更改 version 呢?答案是肯定的,通过查看 SafeIterableMap 的源码我们发现有一个 protectedget 方法。因此,在调用 observe 的时候,我们可以通过反射拿到 LifecycleBoundObserver ,再把 LifecycleBoundObserver 的 version 设置成和 LiveData 一致即可。

为什么 LiveData 可以自动取消订阅?

如果一个 Observer 的生命周期处于 STARTEDRESUMED 状态,那么LiveData 将认为这个 Observer 处于活跃状态,LiveData 仅通知活跃的 Observer 去更新 UI。非活跃状态的 Observer,即使订阅了 LiveData,也不会收到更新的通知。

当页面销毁时,在 mObservers 中 remove 了 observer,就这样完成了订阅的自动取消。

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    removed.detachObserver();
    removed.activeStateChanged(false);
}

感谢:

https://tech.meituan.com/2018/07/26/android-livedatabus.html

相关文章

网友评论

      本文标题:LiveData 你应该知道的知识点

      本文链接:https://www.haomeiwen.com/subject/urmajrtx.html