收到第一个结果后,如何删除观察者?下面是我尝试过的两种代码方式,但即使我已经删除了观察者,它们也都会继续接收更新。
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-> {});
} );
你的第一个将不起作用,因为observeForever()
没有绑定任何LifecycleOwner
。
你的第二个将无法工作,因为你没有将现有的注册观察员传递给removeObserver()
。
你首先要确定你是否使用LiveData
和LifecycleOwner
(你的活动)。我的假设是你应该使用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);
继CommonsWare回答之后,你可以简单地调用removeObservers()
来删除这个观察者,而不是调用removeObserver(this)
来删除附加到LiveData的所有观察者。
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).removeObserver(this);
}
};
model.getDownloadByContentId(contentId).observe((AppCompatActivity)context, observer);
注意:在removeObserver(this)
中,this
引用观察者实例,这仅适用于匿名内部类的情况。如果你使用lambda,那么this
将引用活动实例。
对于带有扩展的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
。
我同意上面的@vince,但我相信我们要么跳过传递lifecycleOwner
并使用observerForever
如下:
fun <T> LiveData<T>.observeOnce(observer: Observer<T>) {
observeForever(object : Observer<T> {
override fun onChanged(t: T?) {
observer.onChanged(t)
removeObserver(this)
}
})
}
或使用lifecycleOwner
与observe
如下:
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)
}
})
}
removeObserver(@NonNull final Observer<T> observer)
(仔细查看方法的名称,它是单数),它接收您想要从同一LifecycleOwner的观察者列表中删除的观察者。
removeObservers(@NonNull final LifecycleOwner owner)
(参见复数方法名称)。此方法接受LifecycleOwner本身并删除指定LifecycleOwner的所有Observers。
现在在你的情况下,你可以通过2种方式删除你的观察者(可能有很多种方式),@ ToniJoe在前一个答案中告诉你。
另一种方法是在ViewModel中有一个布尔值的MutableLiveData,当它第一次被观察时存储为true,并且只是观察Livedata。因此,无论何时转为true,您都会收到通知,并且您可以通过传递该特定观察者来移除您的观察者。
我喜欢@Vince和@Hakem Zaied的通用解决方案,但对我来说lambda版似乎更好:
fun <T> LiveData<T>.observeOnce(observer: (T) -> Unit) {
observeForever(object: Observer<T> {
override fun onChanged(value: T) {
removeObserver(this)
observer(value)
}
})
}
fun <T> LiveData<T>.observeOnce(owner: LifecycleOwner, observer: (T) -> Unit) {
observe(owner, object: Observer<T> {
override fun onChanged(value: T) {
removeObserver(this)
observer(value)
}
})
}
所以你最终得到:
val livedata = model.getDownloadByContentId(contentId)
livedata.observeOnce((AppCompatActivity) context) {
if (it != null) {
DownloadManager.this.downloadManagerListener.onDownloadManagerFailed(null, "this item already exists")
}
startDownload();
}
我觉得更清洁。
此外,当调度观察者时,removeObserver()
被称为第一件事,这使得它更安全(即应对用户观察者代码中潜在的运行时错误抛出)。