I want to show an error message when timeout occurs, but can't find how to do it without passing the loginProgressBar
and loginTimeoutErrorTextview
or other UI related variables. Basically keep the UI changes in the Fragment
.
What i do in my loginFragment
when pressing login
try {
loginViewModel.login(
binding.emailEditText.text.toString(),
binding.passwordEditText.text.toString()
)
} catch (e: IOException) { // THIS doesn't work
binding.loginProgressBar.visibility = View.GONE
binding.loginTimeoutErrorTextview.visibility = View.VISIBLE
}
From what i've found the timeout throws an IOException
so everything is correct here
loginViewModel.login
method:
viewModelScope.launch {
val securedLoginRequest = encodedRequest(username, password)
Log.i("API Login", "Sent data: $securedLoginRequest")
try {
Log.i("API Login", "login started")
// _response is a LiveData<String>
_response.value =
ApiServiceObject.retrofitService.postLogin(securedLoginRequest)
Log.i("API Login", "Login successful, token = ${_response.value}")
} catch (e: IOException) {
throw e // THIS should theoretically get catched by the block above right?
} catch (e: Exception) {
Log.w("API Login", e.toString())
}
}
Problem is the thrown exception in Block 2 doesn't get catched in Block 1
I've found a workaround by simply passing down loginProgressBar
and loginTimeoutErrorTextview
to loginViewModel.login
but is that alright? Isn't there better ways?
UPD: some clarifications
I've found a way, by using a StateFlow
instead of LiveData
in the ViewModel
as follows:
private val _loginState = MutableStateFlow<LoginState>(LoginState.Empty)
val loginState = _loginState.asStateFlow()
sealed class LoginState {
object Empty : LoginState()
object Loading : LoginState()
data class Success(val result: String) : LoginState()
data class Error(val error: Throwable) : LoginState()
}
Then responding to it in the Fragment
like this:
lifecycleScope.launch{
repeatOnLifecycle(Lifecycle.State.STARTED){
loginViewModel.loginState.collect { state ->
binding.loginProgressBar.isGone = state !is LoginState.Loading
when (state) {
is LoginState.Error -> { doSomething() }
is LoginState.Success -> { doSomething() }
else -> Unit
}
}
}
}