加入展平数据是documentation中描述的常见用例。但文档显示了一个非实时的简单示例,它不会对更改做出反应。我正在寻找一个更强大的实现。我认为RxJava非常适合这种情况。
考虑遵循Firebase结构:
{
"messages": {
"group_id_1": {
"message_id_1": {
"text": "Hello",
"author": "uid_1"
}
}
},
"users": {
"uid_1": {
"name": "David"
}
},
"rooms": {
"room_id_1": {
"name": "General",
"members": {
"uid_1": true
}
}
}
}
我在这里看到两个用例:
Observable<Message>
,当我订阅它时,依赖项(这些消息的用户)也将在某些缓存中订阅。当我显示消息时,我可以从缓存中获取作者的姓名。Observable<User>
,当我订阅它时,它会首先订阅房间的成员,然后订阅个人用户。你知道库/解决方案可以做到吗?
或者如果我创建了一个会使用它吗?
答案 0 :(得分:1)
我打算提出这个问题的一个变体,但似乎建立在这个问题之上可能会更好......我将描述什么是希望至少部分地回答上述问题而且还有一个缺点我正在看。
使用上面的数据模型,我们可能会有以下内容来创建围绕firebase查询的RxJava包装,以获取特定空间的成员键列表以及获取特定成员的详细信息(请注意onCompleted()
中subscriber.getMemberInfo
的使用情况} ......稍后再说!)。
public Observable<String> getRoomMembers(String roomId) {
return Observable.create(subscriber -> {
databaseReference.child(roomId + "/members").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String userId = childSnapshot.getKey()
subscriber.onNext(userId);
}
subscriber.onCompleted();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
});
}
public Observable<Member> getMemberInfo(String memberId) {
return Observable.create(subscriber -> {
databaseReference.child(memberId).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Member member = dataSnapshot.getValue(Member.class);
subscriber.onNext(member);
subscriber.onCompleted();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
});
}
然后,我们可以使用以下内容获取特定房间Member
的列表(已将isActive
属性添加到Member
以显示我们如何过滤我们获得的结果)
getRoomMembers(roomId)
.flatMap(memberId -> getMemberInfo(memberId))
.filter(Member::isActive)
.toList()
.subscribe(members -> {
});
因此,上述工作达到了一定程度。问题是,我必须在subscriber.onCompleted()
中致电getMemberInfo
,以便上述flatMap
调用工作....这意味着对Member
数据的任何后续更改都不是在上述订阅中触发更新。对RxJava
和Firebase
来说相对较新,所以可能会遗漏一些明显的东西。
答案 1 :(得分:1)
我最终用这两种方法解决了它(在Kotlin中,Java类似,只是更冗长):
fun <A, B> Observable<List<A>>.mapSubQueries(subQuery: (A) -> Observable<B>): Observable<List<Observable<B>>> {
return this.flatMap {
if (it.isNotEmpty()) {
return@flatMap Observable.from(it).map { subQuery(it) }.toList()
} else {
return@flatMap Observable.just(listOf<Observable<B>>())
}
}
}
@Suppress("UNCHECKED_CAST")
fun <T> Observable<List<Observable<T>>>.joinSubQueries(): Observable<List<T>> {
return this.flatMap {
if (it.isNotEmpty()) {
return@flatMap Observable.combineLatest(it, {
val list = mutableListOf<T>()
it.forEach {
list.add(it as T)
}
list
})
} else {
return@flatMap Observable.just(listOf<T>())
}
}
}
为了让所有消息都能吸引用户,我可以像这样使用它:
fun usersInMessages(roomId): Observable<List<User>> {
return DatabaseRead.messages(roomId)
.mapSubQueries { DatabaseRead.user(it.getAuthor()) }
.joinSubQueries()
}
我决定最好将此代码保存在我的代码库中,并针对各种用例进行稍微修改。使它成为一个库将使其灵活性降低。重点是始终使用Observable.combineLatest()
。许多其他Rx参数都是无用的,因为它们需要onComplete()
调用,在这里我处理无限的Observable。