I was thinking, is there any way to build your code, so you could do Retrofit calls like this:
For e.g in MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val data = userRepository.getUsers().await()
}
CodePudding user response:
The content of the onCreate()
function is called on the main thread. You cannot await long-running actions like IO or Retrofit calls on the main thread.
You can push it to a coroutine like this. All code that must be called in sequence after the data is requested must go inside the coroutine.
You must wrap your call in try/catch when using await or a suspend function to retrieve something in Retrofit, so you can handle any IO errors that occur because the retrieve could not be completed.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
val data = try {
userRepository.getUsers().await()
} catch (e: HttpException) {
// Do something with HTTP failures here.
return@launch
} catch (e: Exception) {
// Do something when connection can't be made here.
return@launch
}
// Do something with data inside the coroutine here.
}
}
Note that if you're using coroutines, you might as well define your function in your API as a suspend function instead of a function that returns a Call, so change something like
@GET("users")
fun getUsers(@Path("users") users: String): Call<List<User>>
into
@GET("users")
suspend fun getUsers(@Path("users") users: String): List<User>
and you won't need the await()
call.
Alternatively, instead of coroutines, you can use a Callback, but it's messier looking code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userRepository.getUsers().enqueue(object: Callback<List<User>> {
override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
if (response.isSuccessful) {
val data = body!!
// Do something with response data here.
} else {
// Do something with HTTP failures here.
}
}
override fun onFailure(call: Call<List<User>>, t: Throwable) {
// Do something when connection can't be made here.
}
})
}
Regardless of whether you use coroutines or not, you should probably doing this request in a ViewModel instead of directly in your Activity. That way the request doesn't have to be remade anew every time the user rotates the screen.