我正在尝试制作一个使用 firestore 的简单应用程序,只需插入设备的令牌并获取与该令牌对应的名称。当我尝试获取“名称”值时,我的帮助程序类中的流程获取了正确的值,但 viewModel 没有获取该值。
我想我从日志中得到了 2 个观察结果->
1.通过查看日志,首先
2024-10-05 09:32:29.658 29752-29808 FirestoreHelperForToken com.example.fcmpractice D Setting up addSnapshotListener
首先我的班级被创建。然后我的 viewModel 尝试访问该值,因此这个日志来了
"2024-10-05 09:32:30.350 29752-29752 ChatViewModel com.example.fcmpractice D List is null "
然后变量的 fetchAllName 正在访问它
"2024-10-05 09:32:30.826 29752-29752 FirestoreHelperForToken com.example.fcmpractice D Snapshot size: 10
2024-10-05 09:32:30.833 29752-29752 FirestoreHelperForToken com.example.fcmpractice D Names list: [mona, abhijit, mahesh, ritu, jodha, madhav, babu, raghav, mamu, nammy] "
也许这就是为什么我的 viewModel 没有获取值。
2.在我的 viewModel 中,这段代码
viewModelScope.launch {
firestoreHelperForToken.fetchAllNames.collect { names ->
_getAllNames.value = names
Log.d("ChatViewModel", "Fetched names from Firestore: $names")
}
}
收集功能内的日志不打印。我不知道为什么。请帮助我获得您的意见和帮助。
这些是我的代码文件,我尝试在每一步中使用日志但无法解决问题。
Helper类(重要部分)
class FirestoreHelperForToken {
val scope = CoroutineScope(Dispatchers.IO)
private val TAG = "FirestoreHelperForToken"
private val _db = Firebase.firestore
val fetchAllNames: Flow<List<String>> = channelFlow {
trySend(emptyList())
Log.d(TAG, "Setting up addSnapshotListener")
_db.collection("tokens")
.addSnapshotListener { snapshot, e ->
if (e != null) {
Log.w(TAG, "Listen failed with error: $e")
return@addSnapshotListener
}
if (snapshot == null || snapshot.isEmpty) {
Log.d(TAG, "Snapshot is null or empty.")
trySend(emptyList()) // Emit empty list if no documents are found
return@addSnapshotListener
}
val namesList = mutableListOf<String>()
Log.d(TAG, "Snapshot size: ${snapshot.size()}")
for (document in snapshot.documents) {
val name = document.getString("name")
name?.let {
namesList.add(it)
}
}
try {
Log.d(TAG, "Names list: $namesList")
trySend(namesList) // Emit the list of names
} catch (sendError: Exception) {
Log.e(TAG, "Error while sending names list: ${sendError.message}")
}
}
}.flowOn(Dispatchers.IO)
}
data class TokenData(
val name: String,
val token: String
)
ViewModel(有关问题的重要部分)
class ChatViewModel
(
private val chatRepository: ChatRepository,
application: Application
) : AndroidViewModel(application) {
val firestoreHelperForToken = FirestoreHelperForToken()
private val _getAllNames = MutableLiveData<List<String>>()
val getAllNames : LiveData<List<String>> get() = _getAllNames
init {
//subscribe to a topic to broadcast the message
viewModelScope.launch {
firestoreHelperForToken.fetchAllNames.collect { namesList ->
_getAllNames.value = namesList
// Log inside the collect block to ensure that the data is fetched
Log.d("ChatViewModel", "List from Firestore: $namesList")
// Small delay to ensure data sync if needed
delay(100)
// Check if list is not null or empty and log it
if (!namesList.isNullOrEmpty()) {
Log.d("ChatViewModel", "Valid list received: $namesList")
} else {
Log.d("ChatViewModel", "Empty list received.")
}
}
// Log outside of the collect block after it finishes fetching
Log.d("ChatViewModel", "List outside the collect block: ${getAllNames.value}")
}
}
应用程序导航
@Composable
fun AppNavigation(viewModel: ChatViewModel,context: Context){
val navController = rememberNavController()
val state = viewModel.state
NavHost(navController = navController, startDestination = "JoinConversation")
{
composable(route = "JoinConversation"){
EnteringTokenScreen(
onJoinConversationClicked = {
navController.navigate("ChatListScreen")
},
name = state.nameText,
onNameChange = viewModel::onNameChange,
onSaveTokenClicked = {
viewModel.insertToken(it,onSameName = {
Toast.makeText(context,"Name already exists",Toast.LENGTH_SHORT).show()
})
}
)
}
composable(route = "ChatListScreen"){
val nameList = viewModel.getAllNames.observeAsState(emptyList())
ChatListScreen(nameList.value)
}
}
}
聊天列表屏幕
@Composable
fun ChatListScreen(nameList : List<String>){
LazyColumn (
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
){
items(nameList){
name->
Text(text = name)
}
}
}
我得到的日志如下
2024-10-05 10:24:09.915 30753-30779 FirestoreHelperForToken com.example.fcmpractice D Setting up addSnapshotListener
2024-10-05 10:24:10.645 30753-30753 ChatViewModel com.example.fcmpractice D List from Firestore: []
2024-10-05 10:24:10.650 30753-30753 FirestoreHelperForToken com.example.fcmpractice D Snapshot size: 12
2024-10-05 10:24:10.670 30753-30753 FirestoreHelperForToken com.example.fcmpractice D Names list: [mona, abhijit, mahesh, ritu, jodha, biru, madhav, babu, sujal, raghav, mamu, nammy]
2024-10-05 10:24:10.751 30753-30753 ChatViewModel com.example.fcmpractice D Empty list received.
2024-10-05 10:24:10.758 30753-30753 ChatViewModel com.example.fcmpractice D List outside the collect block: []
收集viewModel中的Flow,而不是使用
_getAllNames.value = namesList
你应该使用这个
_getAllNames.postValue(namesList)
异步收集值。并且还修改 Helper 类以获取名称为->
fun getNamesFlow() : Flow<List<String>> = callbackFlow {
val collectionRef = _db.collection("tokens")
val listner = collectionRef.addSnapshotListener { snapshot, error ->
if (error != null) {
close(error)
return@addSnapshotListener
}
if (snapshot != null && !snapshot.isEmpty){
val nameList = snapshot.documents.map {
it.getString("name") ?: ""
}
trySend(nameList)
}else{
trySend(emptyList())
}
}
awaitClose {
listner.remove()
}
}
}