改造成功后向房间数据库插入数据,协程问题

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}")
        }
    }
}