ViewModel 的 LiveData 变量为空值,而不是 Flow 中所需的值

问题描述 投票:0回答:1

我正在尝试制作一个使用 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")
    }
}

收集功能内的日志不打印。我不知道为什么。请帮助我获得您的意见和帮助。

这些是我的代码文件,我尝试在每一步中使用日志但无法解决问题。

  1. 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
    )
    
  2. 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}")
        }
    }
    
    
  3. 应用程序导航

    @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)
            }
        }
    }
    
  4. 聊天列表屏幕

    @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: []
    
google-cloud-firestore viewmodel kotlin-coroutines android-livedata kotlin-flow
1个回答
0
投票

收集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()
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.