You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LiveData.observe首参数空值校验及LiveData+MVP架构实践疑问

嘿,咱们来一步步拆解你的问题,结合MVP+LiveData的实践给你梳理清楚~

问题一:listLiveData.observe(getView())的参数要不要校验?

答案是必须要!

你想啊,LiveData.observe()方法的第一个参数是LifecycleOwner(你的View层,比如Activity/Fragment),这个参数是不允许为null的——如果getView()返回null(比如View已经被销毁、Presenter还没detach的场景),直接传进去会立刻抛出NullPointerException,这肯定不是你想要的。

所以在调用observe之前,一定要先加判断:

BasketView currentView = getView();
if (currentView == null) {
    return;
}
listLiveData.observe(currentView, basketItems -> {
    callView(view -> view.setData(basketItems));
});

这里和你的callView方法校验逻辑是一致的,都是为了避免在View已经不可用的情况下执行相关操作,既防止崩溃,也避免无效的UI更新。

问题二:Presenter中获取LiveData并以View作为观察者的做法是否正确?

这个做法是可行的,但有几个关键细节需要注意,不然容易踩内存泄漏或者生命周期的坑:

1. 一定要处理观察者的移除

LiveData会持有LifecycleOwner(也就是你的View)的引用,如果在Presenter detachView的时候不主动移除观察者,当View被销毁后,LiveData还会持有它的引用,就会造成内存泄漏。

所以你需要在detachView方法中添加移除观察者的逻辑:

// 建议在Presenter中保存观察者实例,方便后续移除
private Observer<List<BasketItem>> basketObserver;

public void attachView(BasketView view) {
    this.view = view;
    listLiveData = MyApplication.me().getDatabase().basketDao().getAll();
    // 提前创建观察者实例
    basketObserver = basketItems -> {
        callView(v -> v.setData(basketItems));
    };
    // 校验后再观察
    if (getView() != null) {
        listLiveData.observe(getView(), basketObserver);
    }
}

public void detachView() {
    if (getView() != null && basketObserver != null) {
        listLiveData.removeObserver(basketObserver);
    }
    this.view = null;
}

2. 用弱引用持有View更安全

传统MVP中,如果Presenter直接持有View的强引用,当View销毁但Presenter没被回收时,也会造成内存泄漏。建议把View的引用改成WeakReference:

private WeakReference<BasketView> viewRef;

public void attachView(BasketView view) {
    viewRef = new WeakReference<>(view);
    // ... 其他逻辑
}

private BasketView getView() {
    return viewRef != null ? viewRef.get() : null;
}

3. 关于LiveData的获取时机

Room的Dao方法返回的LiveData是单实例的(多次调用getAll()会拿到同一个LiveData对象),所以不用担心重复观察的问题。但建议在attachView时初始化LiveData和观察者,而不是每次viewIsReady都重新获取,避免不必要的对象创建。

总结一下
  • 调用LiveData.observe()前必须校验getView()是否为null,防止NPE;
  • Presenter持有LiveData并以View为观察者的做法是合理的,但一定要在detachView时移除观察者,同时用弱引用持有View,避免内存泄漏;
  • 你的callView校验逻辑已经很完善,保持这个习惯就好。

内容的提问来源于stack exchange,提问作者ip696

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:19:21