I am reading about Kotlin coroutine in Google 's documentation. I'm adviced to use withContext(Dispacher.IO) to a different thread to main-safety. But I have a problem , fetchData() done before response from server so fetchData() return null result. Any help that I appreciate.
https://developer.android.com/kotlin/coroutines/coroutines-best-practices#main-safe
class GameRemoteDataSource @Inject constructor(val api : GameApi) {
val IODispatcher: CoroutineDispatcher = Dispatchers.IO
suspend fun fetchData() : Resource<ListGameResponse> {
var resource : Resource<ListGameResponse> = Resource.loading(null)
withContext(IODispatcher){
Log.d("AAA Thread 1", "${Thread.currentThread().name}")
api.getAllGame(page = 1).enqueue(object : Callback<ListGameResponse>{
override fun onResponse(
call: Call<ListGameResponse>,
response: Response<ListGameResponse>
) {
if(response.code()==200){
resource = Resource.success(response.body())
}else{
resource = Resource.success(response.body())
}
Log.d("AAA code",response.code().toString())
}
override fun onFailure(call: Call<ListGameResponse>, t: Throwable) {
resource = Resource.error(t.message.toString(),null)
Log.d("AAA Thread", "${Thread.currentThread()}")
}
})
Log.d("AAA Thread", "${Thread.currentThread()}")
Log.d("AAA resource",resource.data.toString()+ resource.status.toString())
}
return resource
}
}
withContext
is not helpful for converting an asynchronous function with callback into suspending code that can be used in a coroutine. It is more applicable to converting synchronous blocking code. Your non-working strategy of creating an empty variable and trying to fill it in the callback to synchronously return is described in the answers to this question.For an asynchronous function with callback, if it returns a single value like your code above, this is typically converted to a suspend function using
suspendCoroutine
orsuspendCancellableCoroutine
. If it returns a series of values over time (calls the callback multiple times), it would be fitting to usecallbackFlow
to convert it to a Flow that can be collected in a coroutine.But it looks like you're using Retrofit, which already has a suspend function alternatives to
enqueue
so you don't need to worry about all this. You can use theawait()
orawaitResponse()
functions instead. In this case,await()
would returnListGameResponse
andawaitResponse()
would returnResponse<ListGameResponse>
. SoawaitResponse()
is better if you need to check the response code.Awaiting returns the response and throws an exception if there's an error, so you can use try/catch instead of adding a failure listener.