kotlin - Kotlin 没有被视图模型调用
问题描述
我正在尝试打电话
override suspend fun getLoginResponse(loginRequest: LoginRequest) = flow {
emit(ApiResult.Loading)
networkCall {
loginService.postLoginResponse(loginRequest)
}.let { apiResult->
apiResult.isSuccessAndNotNull().letOnTrueOnSuspend {
(apiResult.getResult() as? LoginResponse)?.let {
emit(ApiResult.Success(it))
Timber.d(it.toString())
} ?: run { emit(ApiResult.Error(TypeCastException("unknown error.")))
Timber.d(TypeCastException("unknown error."))}
}
}
}.flowOn(Dispatchers.IO)
从我的 viewModel 是这样的:
private fun loginResponse(email: String, password: String, device: String){
viewModelScope.launch {
try {
var loginRequest = LoginRequest(email, password, device)
loginResponseFromServer = loginRepository.getLoginResponse(loginRequest)
.asLiveData(viewModelScope.coroutineContext+Dispatchers.Default)
Timber.d(loginResponseFromServer.toString())
}
catch (e: NetworkErrorException){
validationError.value = "Network communication error!"
}
}
}
当我调试或运行代码时getLoginResponse甚至没有调用。有什么我想念的吗?
解决方案
首先,getLoginResponse
不需要是挂起函数,因为它只是返回一个冷流。如果删除suspend
修饰符,则不需要协程来调用它或将其转换为 LiveData。
其次,构建的 LiveData 在.asLiveData()
第一次激活之前不会开始收集 Flow(保持冷态)。这是该函数的文档。当它接收到第一个观察者时,它变得活跃,但你的代码还没有开始观察它,这就是为什么你的flow
块中的代码永远不会被调用的原因。
您也不需要为 LiveData 指定不同的调度程序。您收集哪个调度程序并不重要,因为收集它不会阻塞代码。
但是,LiveData 不应该在 ViewModel 中收集。它用于 UI 交互。应该从 Fragment 观察 LiveData。
您需要将捕获的网络异常转移到您的flow
构建器中。在创建 Flow 或 LiveData 时不会抛出异常,而是在发出请求时(在 Flow 的执行中)。
我不确定如何重写您的流程构建器以正确捕获,因为它具有我没见过的功能。只是一个提示,但是将许多范围函数链接到一个语句中会使代码难以阅读和推理。
因此,要作为 LiveData 执行此操作,您可以按如下方式更改代码:
private fun loginResponse(email: String, password: String, device: String): LiveData<LoginResponse> {
val loginRequest = LoginRequest(email, password, device)
return loginRepository.getLoginResponse(loginRequest)
.asLiveData()
}
然后在你的 Fragment 中观察它。
然而
LiveData 和 Flow 并不真正适合这个用例,因为您想发出一个请求并获得一个响应。您的存储库应该只公开一个返回响应的挂起函数。然后你的 ViewModel 可以有一个挂起函数,它通过调用存储库的挂起函数来传递响应。
推荐阅读
- python - Selenium 元素不可交互按钮(Python、Windows、Chromedriver)
- google-cloud-platform - YouTube 的自动字幕产生比 Google Speech to Text API 更好的结果(型号:video,UseEnhanced:true)。这怎么可能?
- python - 遇到 ValueError: int() 基数为 10 的无效文字: '' 错误
- javascript - Axios 没有取消我在 ReactJS 中的 HTTP 请求
- javascript - MomentJs 生成不同的日期
- r - 如何在 R 中动态选择数据框中的列
- python - Django Private Files - 如何隐藏它们
- java - java.net.ConnectException:两个微服务之间通过 docker 的连接被拒绝
- animation - SwiftUI VStack 动画看起来坏了 - 动画视图不会改变位置
- python - 计算数值积分的中点