我的观察结果如下:
obs
.doOnNext { logger("Items changed (${it.size})") }
.distinctUntilChanged()
.doOnNext { logger("Items changed (${it.size})- EMIITTED") }
日志如下:
Items changed (7)
Items changed (7)- EMIITTED
Items changed (8)
// => missing EMIITTED message although it.size has changed => WHY?
在默认比较器中使用可比较项的列表似乎在这里失败。为什么?如果观察到的发射列表项的大小已更改,则数据将不同,因此distinctUntilChanged
不应过滤掉新列表。但似乎这里发生了这种情况。为什么?
如果我发出一个将列表大小和项目一一比较的项目列表,我真的需要为distinctUntilChanged
提供自己的比较器吗?
修改
我的obs
基本上如下所示:
obs = Observable.combineLatest(
RxDBDataManager.appsManager.observeList(),
RxDBDataManager.widgetsManager.observeList(),
RxDBDataManager.shortcutsManager.observeList(),
RxDBDataManager.customItemsManager.observeList(),
RxDBDataManager.foldersManager.observeList(),
Function5<List<IDBApp>, List<IDBWidget>, List<IDBShortcut>, List<IDBCustomItem>, List<IDBFolder>, List<IFolderOrSidebarItem>> { t1, t2, t3, t4, t5 ->
val list = ArrayList<IFolderOrSidebarItem>()
list.addAll(t1)
list.addAll(t2)
list.addAll(t3)
list.addAll(t4)
list.addAll(t5)
list
}
.flatMapSingle {
Observable.fromIterable(it)
.filter { it.parentType == parentType && it.parentId == parentId }
.cast(T::class.java)
.toList()
}
.flatMapSingle {
Observable.fromIterable(it)
.sorted(comparator)
.toList()
}
此外,我还使用
对此数据进行了一些排序和过滤答案 0 :(得分:2)
基于评论中的交流:
鼓励RxJava用户在其流中使用不可变的数据类型,以防止发生并发问题,例如在不同阶段从不同线程修改同一对象,从而导致操作员行为中断和看似不可能的业务逻辑故障。
在这种情况下,distinctUntilChanged
不能按预期工作,因为可变项的更改方式是,随后的两个onNext
信号基本上具有相同的内容,并且操作员将其滤除为非完全不同。
检测涉及的项实际上是否无意的一种方法是使用运算符的双谓词版本,然后在自定义lambda中放置一个断点。这样一来,您就可以检查以前的值和当前的值,并查看它们是否真正相等,即使它们不应该是一样的:
source.distinctUntilChanged((prev, curr) -> {
// breakpoint the next line
return prev.equals(curr);
});
在这种情况下,损坏的行为是由于易变项在某处发生了更改,因此其评估结果与当前/上一个相同。对于List
,断点所有突变方法(例如add
,addAll
,set
,remove
等)通常是不切实际的,但是可以将可变列表变成一个不变的列表,并按照顺序发送。内置方法是通过Collections::unmodifiableList
进行转换:
source
.toList()
.map(Collections::unmodifiableList)
;
每当在现在无法修改的列表实例上尝试进行突变时,这就会崩溃,指向应该进一步研究的逻辑。