当前位置: 首页 > 知识库问答 >
问题:

LiveData在第一次回调后删除观察者

长孙朝明
2023-03-14

如何在收到第一个结果后移除观察者?下面是我尝试过的两种代码方式,但它们都不断接收更新,即使我已经删除了观察者。

Observer observer = new Observer<DownloadItem>() {
        @Override
        public void onChanged(@Nullable DownloadItem downloadItem) {
            if(downloadItem!= null) {
                DownloadManager.this.downloadManagerListener.onDownloadManagerFailed(null, "this item already exists");
                return;
            }
            startDownload();
            model.getDownloadByContentId(contentId).removeObservers((AppCompatActivity)context);
        }
    };
    model.getDownloadByContentId(contentId).observeForever(observer);
 model.getDownloadByContentId(contentId).observe((AppCompatActivity)context, downloadItem-> {
             if(downloadItem!= null) {
                this.downloadManagerListener.onDownloadManagerFailed(null, "this item already exists");
                return;
            }
            startDownload();
            model.getDownloadByContentId(contentId).removeObserver(downloadItem-> {});
        } );

共有2个答案

秦俊发
2023-03-14

对于Kotlin来说,有一个更方便的扩展解决方案:

fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
    observe(lifecycleOwner, object : Observer<T> {
        override fun onChanged(t: T?) {
            observer.onChanged(t)
            removeObserver(this)
        }
    })
}

这次延期使我们能够这样做:

liveData.observeOnce(this, Observer<Password> {
    if (it != null) {
        // do something
    }
})

为了回答你原来的问题,我们可以这样做:

val livedata = model.getDownloadByContentId(contentId)
livedata.observeOnce((AppCompatActivity) context, Observer<T> {
    if (it != null) {
        DownloadManager.this.downloadManagerListener.onDownloadManagerFailed(null, "this item already exists");
    }
    startDownload();
})

原始源代码在这里:https://code.luasoftware.com/tutorials/android/android-livedata-observe-once-only-kotlin/

更新:@hakem-zaied是对的,我们需要使用observe而不是observeForever

华宇
2023-03-14

您的第一个将不起作用,因为observeForever()没有绑定到任何LifecyCleOwner

您的第二个将不起作用,因为您没有将现有的已注册观察者传递给removeobserver()

您首先需要确定是否将LiveDataLifecycleOwner(您的activity)一起使用。我的假设是,您应该使用lifecycleowner。在这种情况下,请使用:

Observer observer = new Observer<DownloadItem>() {
    @Override
    public void onChanged(@Nullable DownloadItem downloadItem) {
        if(downloadItem!= null) {
            DownloadManager.this.downloadManagerListener.onDownloadManagerFailed(null, "this item already exists");
            return;
        }
        startDownload();
        model.getDownloadByContentId(contentId).removeObservers((AppCompatActivity)context);
    }
};

model.getDownloadByContentId(contentId).observe((AppCompatActivity)context, observer);
 类似资料:
  • 我想在片段中加载任务,在片段的onviewCreate中,我注册observer,在片段的onResume中,我异步加载任务,当第一次输入片段时,它工作正常,但当我导航到其他片段,然后返回到任务片段时,回调将被调用两次。 我知道如果LiveData已经有了数据集,它将被传递给观察者,因此当返回到任务片段时,在中注册观察者时,将触发,在onResume中,将第二次触发,我想知道如何避免这种情况。我搜

  • 在我正在工作的一个项目中,我使用了paginglibrary和Reverfit。这是我第一次这么做。 数据正常返回。但是我注意到我的viewmodel(更确切地说是我的LiveData)中的观察者在我的PageKeyedDataSource中的LoadIsitial回调之前被调用。这将使传递给适配器的列表为空。为什么在我回调之前调用Observer?

  • 我有一个片段和一个相应的viewmodel类。我在Fragment方法上从DB获取包装为LiveData的联系人列表。它工作得很好,我使用PagedListAdapter显示联系人列表,如下所示: 我在我的片段中添加了一个观察者,如下所示: 有一个按钮在我的片段,它把我带到另一个屏幕,在那个屏幕上我添加更多的联系人到表。但当我从那个屏幕回到我的片段时,观察者并没有被调用。这意味着返回时不会调用方法

  • 此外,为什么Viewmodel不能观察到它自己的LiveData的变化?

  • 我有一个单独的类来处理数据提取(特别是Firebase),我通常从它返回LiveData对象并异步更新它们。现在我希望将返回的数据存储在ViewModel中,但问题是为了获得所述值,我需要观察从数据提取类返回的LiveData对象。observe方法需要一个LifecycleOwner对象作为第一个参数,但我的ViewModel中显然没有这个对象,而且我知道我不应该在ViewModel中保留对ac