https://www.youtube.com/watch?v=NW03ZAQcTuY
某些数据来自其他数据,可以用flow进行一些变形转换
比较简单一点的例子
private val _users = MutableStateFlow(emptyList<User>())
val users = _users.asStateFlow()
// private val _loacalUser= MutableStateFlow<User?>(null)
// val localUser = _loacalUser.asStateFlow()
val localUser = users.map {users->
users.find {
it.id =="local"
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(),null)
private fun onUserJoined(user:User){
_users.update { it+user }
// if(user.id=="local"){
// _loacalUser.update { user }
// }
}
private fun onUserInfoUpdate(user: User){
_users.update {
it.map {curUser->
if(curUser.id == user.id) user else curUser //id一样,替换掉,否则还是原来的
}
}
// if(user.id=="local"){
// _loacalUser.update { user }
// }
}
上面,本地用户其实是用户列表中的一个特殊用户,他的ID是local。
如果我们分开存储,像刚开始被注释掉的那些代码,用一个单独的localuser来存储本地用户,当用户列表变化的时候,需要监测是不是local,如果是local,要更新localuser,
当用户信息变化的时候,需要监测下,当前是不是localuser,如果是,则localuser又要更新一下
这样,当方法多了以后,非常麻烦,也容易忘记检查是否是local
于是就取消的localuser的当初存储,而是让他从user list 变化而来
把userlist map 变形,再找到是local的那个用户,然后在statein scope中,以便 引用。
稍微再复杂一点的还给出了一个聊天室的状态
class ChatViewModel : ViewModel() {
private val _isLoggedIn = MutableStateFlow(false)
private val _chatMessages = MutableStateFlow(emptyList<ChatMessage>())
private val _users = MutableStateFlow<List<User>>(emptyList())
val chatState = combine(_isLoggedIn,_chatMessages,_users){ isLoggedIn,chatMessages,users->
if(isLoggedIn){
ChatState(users.map { curUser->
ChatPreview(curUser,
chatMessages.filter { it.user.id==curUser.id }
.maxByOrNull { it.time }
?.message)
})
}else{
null
}
}
}
data class ChatState(val chatPreviews: List<ChatPreview>)
data class ChatPreview(
val user: User,
val latestMessage: String?
)
data class ChatMessage(
val user: User,
val message: String, val time: Long
)
data class User(
val id: String,
val name: String,
val email: String,
val phone: String
)
针对每个个用户的聊天预览列表有多个因素影响,是否登录,用户列表,消息列表
然后根据这三个的数据combine生成一个chatstate的数据
其中 chatpreview中的最新消息,是把所有消息,根据当前用户的过滤后,再找出最近的时间的那条,再取message