改造成功后将数据插入房间数据库,协程问题
Posted
技术标签:
【中文标题】改造成功后将数据插入房间数据库,协程问题【英文标题】:Insert Data into room database after retrofit success, coroutine problem 【发布时间】:2020-10-05 01:47:40 【问题描述】:我正在使用 Retrofit 从 API 服务器获取新闻记录,如果成功,它将使用 insertAll 将数据写入房间数据库,如下面的代码,但此代码会产生如下错误 无法访问主线程上的数据库,因为它可能会长时间锁定 UI
我尝试使用 Coroutine,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")
)
【问题讨论】:
我的回答不能解决你的问题吗? @DominicFischer 我确实为您的答案标记了+1,但仍未测试您的答案,感谢您的详细解释 【参考方案1】:您的代码应该看起来更像这样。用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")
【讨论】:
java.lang.IllegalStateException: 无法在后台线程上调用 setValue。我正在收到此异常 代码中没有setValue
。您可能正在使用withContext(Dispatchers.IO)
并在其中调用setValue
。
是的,我需要从数据库中获取列表的大小,因为我正在使用 livedata value.size
我认为你应该问一个新问题,我没有太多信息可以参考。
@DominicFischer 嗨,我需要做几乎相同的事情,但使用 java。你能看看我的问题吗?我已经设置好了所有东西我只是不知道在哪里做插入():如果 onResponse 或其他地方:***.com/questions/68602466/…以上是关于改造成功后将数据插入房间数据库,协程问题的主要内容,如果未能解决你的问题,请参考以下文章
为啥在执行成功的 bigquery 插入后将其存储在时态表中?