如何在 ViewModel 中观察存储库 class 中的 return 值?
How to observe the return value from a Repository class in a ViewModel?
我有一个使用 MVVM 架构的 android 应用程序。在单击按钮时,我启动了一个调用 ViewModel 方法来发出网络请求的协程。在我的 ViewModel 中,我有一个 LiveData 可观察到该请求的 return,但我没有看到它更新。似乎我的存储库方法没有被调用,我不确定为什么。
UI 点击监听器
searchButton.setOnClickListener{
CoroutineScope(IO).launch{
viewModel.getUser(username.toString())
}
}
ViewModel - Observable 和调用的方法
private var _user: MutableLiveData<User?> = MutableLiveData<User?>()
val user: LiveData <User?>
get() = _user
...
suspend fun getUser(userId:String) {
_user = liveData{
emit(repository.getUser(userId))
} as MutableLiveData<User?>
}
...
当我调试通过时,执行进入了 ViewModel 的 getUser 方法,但没有进入 liveData 范围来更新我的 _user MutableLiveData observable,我不确定我做错了什么。
不需要使用 liveData
协程生成器,因为 getUser
是一个挂起的函数,您已经在协程中调用它了。只是 post 结果只是 _user
.
suspend fun getUser(userId: String) {
_user.postValue(repository.getUser(userId))
}
您对代码所做的操作导致将 LiveData
的新实例分配给 _user
,而片段中的观察者正在观察由 [= 实例化的前一个 LiveData
19=]。因此,更新丢失了。
更好的解决方案是在 ViewModel
class 中处理协同程序的创建,以跟踪它们并防止执行泄漏。
fun getUser(userId: String) {
viewModelScope.launch(IO) {
_user.postValue(repository.getUser(userId))
}
}
片段中:
searchButton.setOnClickListener{
viewModel.getUser(username.toString())
}
它不起作用,因为您的“MVVM 结构”没有遵循 MVVM 建议,也没有遵循为协程提供的结构化并发指南。
searchButton.setOnClickListener{
CoroutineScope(IO).launch{ // <-- should be using a controlled scope
viewModel.getUser(username.toString()) // <-- state belongs in the viewModel
}
}
相反,它应该看起来像这样
searchButton.setOnClickListener {
viewModel.onSearchButtonClicked()
}
username.doAfterTextChanged {
viewModel.updateUsername(it)
}
和
class MyViewModel(
private val application: Application,
private val savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {
private val repository = (application as CustomApplication).repository
private val username = savedStateHandle.getLiveData("username", "")
fun updateUsername(username: String) {
username.value = username
}
val user: LiveData<User?> = username.switchMap { userId ->
liveData(viewModelScope + Dispatchers.IO) {
emit(repository.getUser(userId))
}
}
}
现在您可以 user.observe(viewLifecycleOwner) { user -> ... }
并且应该可以了。如果您真的只需要在单击按钮时获取数据,您可能希望将 liveData {
替换为常规 suspend fun
调用,从 viewModelScope.launch {
调用,并将值保存到 LiveData .
我有一个使用 MVVM 架构的 android 应用程序。在单击按钮时,我启动了一个调用 ViewModel 方法来发出网络请求的协程。在我的 ViewModel 中,我有一个 LiveData 可观察到该请求的 return,但我没有看到它更新。似乎我的存储库方法没有被调用,我不确定为什么。
UI 点击监听器
searchButton.setOnClickListener{
CoroutineScope(IO).launch{
viewModel.getUser(username.toString())
}
}
ViewModel - Observable 和调用的方法
private var _user: MutableLiveData<User?> = MutableLiveData<User?>()
val user: LiveData <User?>
get() = _user
...
suspend fun getUser(userId:String) {
_user = liveData{
emit(repository.getUser(userId))
} as MutableLiveData<User?>
}
...
当我调试通过时,执行进入了 ViewModel 的 getUser 方法,但没有进入 liveData 范围来更新我的 _user MutableLiveData observable,我不确定我做错了什么。
不需要使用 liveData
协程生成器,因为 getUser
是一个挂起的函数,您已经在协程中调用它了。只是 post 结果只是 _user
.
suspend fun getUser(userId: String) {
_user.postValue(repository.getUser(userId))
}
您对代码所做的操作导致将 LiveData
的新实例分配给 _user
,而片段中的观察者正在观察由 [= 实例化的前一个 LiveData
19=]。因此,更新丢失了。
更好的解决方案是在 ViewModel
class 中处理协同程序的创建,以跟踪它们并防止执行泄漏。
fun getUser(userId: String) {
viewModelScope.launch(IO) {
_user.postValue(repository.getUser(userId))
}
}
片段中:
searchButton.setOnClickListener{
viewModel.getUser(username.toString())
}
它不起作用,因为您的“MVVM 结构”没有遵循 MVVM 建议,也没有遵循为协程提供的结构化并发指南。
searchButton.setOnClickListener{
CoroutineScope(IO).launch{ // <-- should be using a controlled scope
viewModel.getUser(username.toString()) // <-- state belongs in the viewModel
}
}
相反,它应该看起来像这样
searchButton.setOnClickListener {
viewModel.onSearchButtonClicked()
}
username.doAfterTextChanged {
viewModel.updateUsername(it)
}
和
class MyViewModel(
private val application: Application,
private val savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {
private val repository = (application as CustomApplication).repository
private val username = savedStateHandle.getLiveData("username", "")
fun updateUsername(username: String) {
username.value = username
}
val user: LiveData<User?> = username.switchMap { userId ->
liveData(viewModelScope + Dispatchers.IO) {
emit(repository.getUser(userId))
}
}
}
现在您可以 user.observe(viewLifecycleOwner) { user -> ... }
并且应该可以了。如果您真的只需要在单击按钮时获取数据,您可能希望将 liveData {
替换为常规 suspend fun
调用,从 viewModelScope.launch {
调用,并将值保存到 LiveData .