改造成功后向房间数据库插入数据,协程问题
Insert Data into room database after retrofit success, coroutine problem
我正在使用 Retrofit 从 API 服务器获取新闻记录,如果成功,它将使用 insertAll 将数据写入房间数据库,如下代码所示,但此代码会产生如下错误
无法在主线程上访问数据库,因为它可能会长时间锁定 UI
我尝试使用协程,withContext(Dispatchers.IO) 但我认为它不正确,感谢您的帮助
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}")
}
}
})
}
}
您的代码应该看起来更像这样。使用 suspendCoroutine
隔离回调代码,以便 withContext(Dispatchers.IO)
之类的东西按预期工作。
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}")
}
}
}
编辑:
理想情况下,您想为此创建一个扩展函数,这样读起来就不会那么吓人了。
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}")
}
}
}
我正在使用 Retrofit 从 API 服务器获取新闻记录,如果成功,它将使用 insertAll 将数据写入房间数据库,如下代码所示,但此代码会产生如下错误 无法在主线程上访问数据库,因为它可能会长时间锁定 UI
我尝试使用协程,withContext(Dispatchers.IO) 但我认为它不正确,感谢您的帮助
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}")
}
}
})
}
}
您的代码应该看起来更像这样。使用 suspendCoroutine
隔离回调代码,以便 withContext(Dispatchers.IO)
之类的东西按预期工作。
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}")
}
}
}
编辑:
理想情况下,您想为此创建一个扩展函数,这样读起来就不会那么吓人了。
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}")
}
}
}