观察回调没有被 Kotlin 协程 Flow 和 LiveData 触发?
Observe callback is not being triggered with Kotlin coroutines Flow and LiveData?
我是 Android 开发的新手,正在尝试从各种示例项目中了解协程和 LiveData
。我目前已经设置了一个函数来在用户输入用户名和密码时调用我的api。然而,在按下 1 个按钮后,应用程序似乎卡住了,我无法再进行 api 调用,就好像它卡在了一个挂起的进程中一样。
这是我的第一个 android 应用,融合了很多想法,所以请让我知道哪里出错了!
Activity:
binding.bLogin.setOnClickListener {
val username = binding.etUsername.text.toString()
val password = binding.etPassword.text.toString()
viewModel.userClicked(username, password).observe(this, Observer {
it?.let { resource ->
when (resource.status) {
Status.SUCCESS -> {
print(resource.data)
}
Status.ERROR -> {
print(resource.message)
}
Status.LOADING -> {
// loader stuff
}
}
}
})
}
视图模型:
fun userClicked(username: String, password: String) = liveData(dispatcherIO) {
viewModelScope.launch {
emit(Resource.loading(data = null))
try {
userRepository.login(username, password).apply {
emit(Resource.success(null))
}
} catch (exception: Exception) {
emit(Resource.error(exception.message ?: "Error Occurred!", data = null))
}
}
}
存储库:
@WorkerThread
suspend fun login(
username: String,
password: String
): Flow<Resource<String?>> {
return flow {
emit(Resource.loading(null))
api.login(LoginRequest(username, password)).apply {
this.onSuccessSuspend {
data?.let {
prefs.apiToken = it.key
emit(Resource.success(null))
}
}
}.onErrorSuspend {
emit(Resource.error(message(), null))
}.onExceptionSuspend {
emit(Resource.error(message(), null))
}
}.flowOn(dispatcherIO)
}
API:
suspend fun login(@Body request: LoginRequest): ApiResponse<Auth>
您不需要在 liveData
构建器中启动协程,它已经 suspend
因此您可以在那里调用 suspend
函数:
fun userClicked(username: String, password: String) = liveData(dispatcherIO) {
emit(Resource.loading(data = null))
try {
userRepository.login(username, password).apply {
emit(Resource.success(null))
}
} catch (exception: Exception) {
emit(Resource.error(exception.message ?: "Error Occurred!", data = null))
}
}
如果您想将 LiveDate
与 Flow
一起使用,您可以使用 asLiveData
函数将 Flow
转换为 LiveData
对象:
fun userClicked(username: String, password: String): LiveData<Resource<String?>> {
return userRepository.login(username, password).asLiveData()
}
但我不建议在项目中混用 LiveData
和 Flow
流。我建议只使用 Flow
.
仅使用 Flow
:
// In ViewModel:
fun userClicked(username: String, password: String): Flow<Resource<String?>> {
return userRepository.login(username, password)
}
// Activity
binding.bLogin.setOnClickListener {
val username = binding.etUsername.text.toString()
val password = binding.etPassword.text.toString()
lifecycleScope.launch {
viewModel.userClicked(username, password).collect { resource ->
when (resource.status) {
Status.SUCCESS -> {
print(resource.data)
}
Status.ERROR -> {
print(resource.message)
}
Status.LOADING -> {
// loader stuff
}
}
}
}
}
从 Repository
中的 login
函数中删除 suspend
关键字。
我是 Android 开发的新手,正在尝试从各种示例项目中了解协程和 LiveData
。我目前已经设置了一个函数来在用户输入用户名和密码时调用我的api。然而,在按下 1 个按钮后,应用程序似乎卡住了,我无法再进行 api 调用,就好像它卡在了一个挂起的进程中一样。
这是我的第一个 android 应用,融合了很多想法,所以请让我知道哪里出错了!
Activity:
binding.bLogin.setOnClickListener {
val username = binding.etUsername.text.toString()
val password = binding.etPassword.text.toString()
viewModel.userClicked(username, password).observe(this, Observer {
it?.let { resource ->
when (resource.status) {
Status.SUCCESS -> {
print(resource.data)
}
Status.ERROR -> {
print(resource.message)
}
Status.LOADING -> {
// loader stuff
}
}
}
})
}
视图模型:
fun userClicked(username: String, password: String) = liveData(dispatcherIO) {
viewModelScope.launch {
emit(Resource.loading(data = null))
try {
userRepository.login(username, password).apply {
emit(Resource.success(null))
}
} catch (exception: Exception) {
emit(Resource.error(exception.message ?: "Error Occurred!", data = null))
}
}
}
存储库:
@WorkerThread
suspend fun login(
username: String,
password: String
): Flow<Resource<String?>> {
return flow {
emit(Resource.loading(null))
api.login(LoginRequest(username, password)).apply {
this.onSuccessSuspend {
data?.let {
prefs.apiToken = it.key
emit(Resource.success(null))
}
}
}.onErrorSuspend {
emit(Resource.error(message(), null))
}.onExceptionSuspend {
emit(Resource.error(message(), null))
}
}.flowOn(dispatcherIO)
}
API:
suspend fun login(@Body request: LoginRequest): ApiResponse<Auth>
您不需要在 liveData
构建器中启动协程,它已经 suspend
因此您可以在那里调用 suspend
函数:
fun userClicked(username: String, password: String) = liveData(dispatcherIO) {
emit(Resource.loading(data = null))
try {
userRepository.login(username, password).apply {
emit(Resource.success(null))
}
} catch (exception: Exception) {
emit(Resource.error(exception.message ?: "Error Occurred!", data = null))
}
}
如果您想将 LiveDate
与 Flow
一起使用,您可以使用 asLiveData
函数将 Flow
转换为 LiveData
对象:
fun userClicked(username: String, password: String): LiveData<Resource<String?>> {
return userRepository.login(username, password).asLiveData()
}
但我不建议在项目中混用 LiveData
和 Flow
流。我建议只使用 Flow
.
仅使用 Flow
:
// In ViewModel:
fun userClicked(username: String, password: String): Flow<Resource<String?>> {
return userRepository.login(username, password)
}
// Activity
binding.bLogin.setOnClickListener {
val username = binding.etUsername.text.toString()
val password = binding.etPassword.text.toString()
lifecycleScope.launch {
viewModel.userClicked(username, password).collect { resource ->
when (resource.status) {
Status.SUCCESS -> {
print(resource.data)
}
Status.ERROR -> {
print(resource.message)
}
Status.LOADING -> {
// loader stuff
}
}
}
}
}
从 Repository
中的 login
函数中删除 suspend
关键字。