I'm making an Android app and i'm trying to make a login. I made a basic retofit request and it works, but i want to handle the response from the server with a generic class, to show error to the user (for example email/password wrong). I follow this tutorial https://blog.mindorks.com/using-retrofit-with-kotlin-coroutines-in-android but here he make the request in the viewModel and access to the data stored in Resource in the mainActivity (the view class). I want to access data in the viewModel to save some information in shared preferences (look the comment in the first code block), but I don't know how to do this. Can someone explain me how to change the code to have access to data in Resource from the ViewModel? Here is my viewModel:
class LoginViewModel(private val loginRepo: LoginRepository) : ViewModel() {
private fun makeLogin(email: String, password: String) {
viewModelScope.launch {
Resource.loading(data = null)
try {
val usr = User(email, password)
Resource.success(data = loginRepo.makeLogin(usr))
// HERE I WANT TO ACCESS TO DATA TO STORE SOME INFORMATION IN SHARED PREFERENCES
} catch (ex: Exception) {
Resource.error(data = null, message = ex.message ?: "Error occured!")
}
}
here is the resource class:
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
companion object {
fun <T> success(data: T): Resource<T> = Resource(status = Status.SUCCESS, data = data, message = null)
fun <T> error(data: T?, message: String): Resource<T> =
Resource(status = Status.ERROR, data = data, message = message)
fun <T> loading(data: T?): Resource<T> = Resource(status = Status.LOADING, data = data, message = null)
}
}
here is the Repository:
class LoginRepository(private val apiHelper: ApiHelper) {
suspend fun makeLogin(usr: User) = apiHelper.makeLogin(usr)
}
The return type of apiHelper.makeLogin(usr) is:
@JsonClass(generateAdapter = true)
data class LoginResponse(
val token: String,
val expiration: String,
val id : Int,
val role: Int)
The viewModel of the tutorial:
class MainViewModel(private val mainRepository: MainRepository) : ViewModel() {
fun getUsers() = liveData(Dispatchers.IO) {
emit(Resource.loading(data = null))
try {
emit(Resource.success(data = mainRepository.getUsers()))
} catch (exception: Exception) {
emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
}
}
}
In the tutorial he access the data stored in Resource in the main activity like this:
viewModel.getUsers().observe(this, Observer {
it?.let { resource ->
when (resource.status) {
SUCCESS -> {
recyclerView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
resource.data?.let { users -> retrieveList(users) }
}
ERROR -> {
recyclerView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
}
LOADING -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
}
}
})
You can do that simply by:
class LoginViewModel(private val loginRepo: LoginRepository) : ViewModel() {
private fun makeLogin(email: String, password: String) {
viewModelScope.launch {
Resource.loading(data = null)
try {
val usr = User(email, password)
val response = loginRepo.makeLogin(usr)
Resource.success(data = response)
// HERE YOU HAVE ACCESS TO RESPONSE TO DO WHATEVER YOU WANT WITH IT
} catch (ex: Exception) {
Resource.error(data = null, message = ex.message ?: "Error occured!")
}
}