Reputation: 6253
I'm using Retrofit to get news record from API server, if it success then it will write data to room database as code below using insertAll, but this code generate an error as follow Cannot access database on the main thread since it may potentially lock the UI for a long period of time
I tried to use Coroutine, withContext(Dispatchers.IO) but I think it's not correct, thank you for any help
suspend fun refreshNews(queryString: String="", page: Int = 1) {
withContext(Dispatchers.IO) {
RetrofitClient.instance.getAllNews(buatObjectNewsQuery(queryString), page)
.enqueue(object : Callback<NewsGetAllResponse> {
override fun onFailure(call: Call<NewsGetAllResponse>, t: Throwable) {
Timber.tag(TAG).i("sorry network error")
}
override fun onResponse(
call: Call<NewsGetAllResponse>,
response: Response<NewsGetAllResponse>
) {
val newslist = response.body()?.asDatabaseModel()
if (newslist != null) {
database.databaseNewsDao.insertAll(*newslist)
Timber.tag(TAG).i("dalam refresh jumlah data ${newslist.size}")
}
}
})
}
}
Upvotes: 1
Views: 1062
Reputation: 1849
You code should look more like this. Isolating the callback code with suspendCoroutine
so that stuff like withContext(Dispatchers.IO)
works as you expect.
suspend fun refreshNews(queryString: String="", page: Int = 1) {
val call = RetrofitClient.instance.getAllNews(buatObjectNewsQuery(queryString), page)
val response = suspendCoroutine { cont ->
call.enqueue(object : Callback<NewsGetAllResponse> {
override fun onFailure(call: Call<NewsGetAllResponse>, t: Throwable) {
cont.resumeWithException(t)
}
override fun onResponse(
call: Call<NewsGetAllResponse>,
response: Response<NewsGetAllResponse>
) {
const.resume(response)
}
})
}
val newslist = response.body()?.asDatabaseModel()
if (newslist != null) {
withContext(Dispatchers.IO) {
database.databaseNewsDao.insertAll(*newslist)
Timber.tag(TAG).i("dalam refresh jumlah data ${newslist.size}")
}
}
}
EDIT:
Ideally you want to make an extension function for that, so it doesn't look so intimidating to read.
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
suspend fun refreshNews(queryString: String="", page: Int = 1) {
val call = RetrofitClient.instance.getAllNews(buatObjectNewsQuery(queryString), page)
val response = call.awaitResponse()
val newslist = response.body()?.asDatabaseModel()
if (newslist != null) {
withContext(Dispatchers.IO) {
database.databaseNewsDao.insertAll(*newslist)
Timber.tag(TAG).i("dalam refresh jumlah data ${newslist.size}")
}
}
}
Upvotes: 1