我有一个访问数据库(Firebase)和统计文档的ViewModel。数据库的结构如下:收藏“帖子”-->文档-->收藏“喜欢”-->文档。因此,我访问集合“Posts”,然后对于每个包含我用户名的文档,我访问集合“Likes”,并获得快照大小来计算有多少个喜欢。问题是,当创建新的Like文档时,ViewModel在应用重新启动之前不会获得更新。
**我使用ViewModel的方式:**我有一个导航图,在那里我创建了一个ViewModel的示例,然后我调用检索数据的函数,然后我将这个示例作为参数传递到需要数据的另一个屏幕中。在另一个屏幕中,我访问存储数据的变量。StateFlow中存储数据的变量(因为我传递的是计数器值而不是文档)
编码(ViewModel):
class PointsViewModel : ViewModel() {
private val firebase = Firebase.firestore
private var _points = MutableStateFlow(0)
val points: StateFlow<Int> = _points
fun calculate(username: String){
firebase.collection("Posts")
.whereEqualTo("PostUser",username)
.get()
.addOnSuccessListener { posts ->
for(post in posts){
post.reference.collection("Likes").get().addOnSuccessListener { likes ->
_points.value += likes.size()
}
}
}
}
}
代码(我在NavGraph中创建示例的地方):
val pointsViewModel: PointsViewModel = viewModel()
//sharedViewModel contains the username
sharedViewModel.user?.username?.let { pointsViewModel.calculate(it) }
代码(我需要数据的地方):
fun AwardsScreen(sharedViewModel: SharedViewModel,pointsViewModel: PointsViewModel){
val points by pointsViewModel.points.collectAsState()
Column(modifier = Modifier
.fillMaxWidth()
.padding(15.dp, 15.dp)) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
Text(text = points.toString())
}
}
我试着在屏幕内做所有这些操作我需要数据。因此,我尝试访问数据库并从中检索所有数据,添加一个snapshotListener来获取更新,但没有成功
2条答案
按热度按时间3pmvbmvn1#
这不是你应该做的时候,当涉及到计数器在Firestore。当您像现在这样计算文档时,查询返回的每个文档都会花费您一次读取,当涉及到更多的喜欢时,这可能会很昂贵。不幸的是,count()不提供实时更新。但是,如果您自己创建和维护一个计数器,它将更便宜。它可以简单地是文档中存在的number类型的字段。这意味着每次向集合中添加新文档时,您只需增加计数器,并在删除文档时减少计数器。在此文档中,您可以附加一个实时侦听器,您将拥有一个始终处于最新状态的计数器。这意味着,为了显示喜欢的数量,你只需要为一次阅读付费。
这样的操作不应该在客户端代码中执行,而应该在可信的环境中执行。所以我建议你在Cloud Functions for Firebase中写一个函数,它可以自动为你完成这个任务。
hyrbngr72#
首先,只是一个小问题,
_points
可以是val
,实际上应该是,因为你不想改变实际示例,只想改变它的值。我注意到的另一件事是,您使用的是
+=
操作数,这可能是这里的罪魁祸首。尝试分配一个新的值,如_points.value = _points.value + likes.size()
。医生说
对于赋值操作,例如a += B,编译器执行以下步骤:
如果右列中的功能可用:
如果相应的二进制函数(意味着plusAssign()的plus())也可用,则a是可变变量,并且plus的返回类型是a类型的子类型,则报告错误(歧义)。
确保其返回类型为Unit,否则报告错误。
生成.plusAssign(B)的代码。
否则,尝试为a = a + B生成代码(这包括类型检查:a + B的类型必须是a)的子类型。
它可能需要一个全新的值,而不需要在赋值中引用自身。
最后,我会建议使用状态保持器。所以你会有一个这样的类:
你可以在
viewModel
中这样使用它:最后,观察它在一个组合: