如何从非挂起回调函数中从 LiveData 构建器发出
How to emit from a LiveData builder from a non-suspending callback function
我是 LiveData 和 Kotlin 协程的新手。我正在尝试使用 Chromium Cronet library to make a request from my repository class to return a LiveData object. To return the liveData, I'm using the new LiveData builder (coroutines with LiveData)。我将如何发出成功的 Cronet 请求的结果?
class CustomRepository @Inject constructor(private val context: Context, private val gson: Gson) : Repository {
private val coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
override suspend fun getLiveData(): LiveData<List<MyItem>> = liveData(coroutineDispatcher) {
val executor = Executors.newSingleThreadExecutor()
val cronetEngineBuilder = CronetEngine.Builder(context)
val cronetEngine = cronetEngineBuilder.build()
val requestBuilder = cronetEngine.newUrlRequestBuilder(
"http://www.exampleApi.com/example",
CustomRequestCallback(gson),
executor
)
val request: UrlRequest = requestBuilder.build()
request.start()
}
class CustomRequestCallback(private val gson: Gson) : UrlRequest.Callback() {
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
byteBuffer?.flip()
byteBuffer?.let {
val byteArray = ByteArray(it.remaining())
it.get(byteArray)
String(byteArray, Charset.forName("UTF-8"))
}.apply {
val myItems = gson.fromJson(this, MyItem::class.java)
// THIS IS WHAT I WANT TO EMIT
// emit(myItems) doesn't work since I'm not in a suspending function
}
byteBuffer?.clear()
request?.read(byteBuffer)
}
// other callbacks not shown
}
}
解决方案涉及将 UrlRequest.Callback
传统回调结构包装在 suspendCoroutine
构建器中。
我也在 Medium article which discusses Cronet integration with LiveData and Kotlin Coroutines.
中记录了我的学习
override suspend fun getLiveData(): LiveData<List<MyItem>> = liveData(coroutineDispatcher) {
lateinit var result: List<MyItem>
suspendCoroutine<List<MyItem>> { continuation ->
val requestBuilder = cronetEngine.newUrlRequestBuilder(
"http://www.exampleApi.com/example",
object : UrlRequest.Callback() {
// other callbacks not shown
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
byteBuffer?.flip()
byteBuffer?.let {
val byteArray = ByteArray(it.remaining())
it.get(byteArray)
String(byteArray, Charset.forName("UTF-8"))
}.apply {
val myItems = gson.fromJson(this, MyItem::class.java)
result = myItems
continuation.resume(result)
}
byteBuffer?.clear()
request?.read(byteBuffer)
},
executor
)
val request: UrlRequest = requestBuilder.build()
request.start()
}
emit(result)
}
我是 LiveData 和 Kotlin 协程的新手。我正在尝试使用 Chromium Cronet library to make a request from my repository class to return a LiveData object. To return the liveData, I'm using the new LiveData builder (coroutines with LiveData)。我将如何发出成功的 Cronet 请求的结果?
class CustomRepository @Inject constructor(private val context: Context, private val gson: Gson) : Repository {
private val coroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
override suspend fun getLiveData(): LiveData<List<MyItem>> = liveData(coroutineDispatcher) {
val executor = Executors.newSingleThreadExecutor()
val cronetEngineBuilder = CronetEngine.Builder(context)
val cronetEngine = cronetEngineBuilder.build()
val requestBuilder = cronetEngine.newUrlRequestBuilder(
"http://www.exampleApi.com/example",
CustomRequestCallback(gson),
executor
)
val request: UrlRequest = requestBuilder.build()
request.start()
}
class CustomRequestCallback(private val gson: Gson) : UrlRequest.Callback() {
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
byteBuffer?.flip()
byteBuffer?.let {
val byteArray = ByteArray(it.remaining())
it.get(byteArray)
String(byteArray, Charset.forName("UTF-8"))
}.apply {
val myItems = gson.fromJson(this, MyItem::class.java)
// THIS IS WHAT I WANT TO EMIT
// emit(myItems) doesn't work since I'm not in a suspending function
}
byteBuffer?.clear()
request?.read(byteBuffer)
}
// other callbacks not shown
}
}
解决方案涉及将 UrlRequest.Callback
传统回调结构包装在 suspendCoroutine
构建器中。
我也在 Medium article which discusses Cronet integration with LiveData and Kotlin Coroutines.
中记录了我的学习override suspend fun getLiveData(): LiveData<List<MyItem>> = liveData(coroutineDispatcher) {
lateinit var result: List<MyItem>
suspendCoroutine<List<MyItem>> { continuation ->
val requestBuilder = cronetEngine.newUrlRequestBuilder(
"http://www.exampleApi.com/example",
object : UrlRequest.Callback() {
// other callbacks not shown
override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
byteBuffer?.flip()
byteBuffer?.let {
val byteArray = ByteArray(it.remaining())
it.get(byteArray)
String(byteArray, Charset.forName("UTF-8"))
}.apply {
val myItems = gson.fromJson(this, MyItem::class.java)
result = myItems
continuation.resume(result)
}
byteBuffer?.clear()
request?.read(byteBuffer)
},
executor
)
val request: UrlRequest = requestBuilder.build()
request.start()
}
emit(result)
}