对 Kotlin 协程的现有3个函数回调

我有一个一般性的问题和一个具体的例子: 我想使用 Kotlin 协程魔术而不是回调在 Android 地狱时拍照。

manager.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
println("Camera onOpened")
// even more callbacks with openedCameraDevice.createCaptureRequest()....
}


override fun onDisconnected(cameraDevice: CameraDevice) {
println("Camera onDisconnected")
cameraDevice.close()
}
...

我怎么才能把它变得不那么丑陋呢?如果是的话,我是否应该使用协同程序来实现异步?

我喜欢使用异步和。等待结果

manager.open(cameraId).await().createCaptureRequest()

我试图通过下面这样的方法来做,但是我不认为我使用的 CompletableDeferred是正确的!

suspend fun CameraManager.open(cameraId:String): CameraDevice {
val response = CompletableDeferred<CameraDevice>()
this.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(cameraDevice: CameraDevice) {
println("camera onOpened $cameraDevice")
response.complete(cameraDevice)
}


override fun onDisconnected(cameraDevice: CameraDevice) {
response.completeExceptionally(Exception("Camera onDisconnected $cameraDevice"))
cameraDevice.close()
}


override fun onError(cameraDevice: CameraDevice, error: Int) {
response.completeExceptionally(Exception("Camera onError $cameraDevice $error"))
cameraDevice.close()
}
}, Handler())
return response.await()
}
28723 次浏览

I've used 2 solutions for this type of thing.

1: wrap the interface in an extension

CameraDevice.openCamera(cameraId: Integer,
onOpenedCallback: (CameraDevice) -> (),
onDisconnectedCallback: (CameraDevice) ->()) {


manager.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpenedCallback(openedCameraDevice)
}


override fun onDisconnected(cameraDevice: CameraDevice) {
onDisconnectedCallback(cameraDevice)
}
})
}

2: Make a simple container class with a more functional interface:

class StateCallbackWrapper(val onOpened: (CameraDevice) -> (), val onClosed: (CameraDevice) ->()): CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpened(openedCameraDevice)
}


override fun onDisconnected(cameraDevice: CameraDevice) {
onClosed(cameraDevice)
}
}

Personally I would start with something like these, and then build whatever threading differences on top of that.

In this particular case you can use a general approach to convert a callback-based API to a suspending function via suspendCoroutine function:

suspend fun CameraManager.openCamera(cameraId: String): CameraDevice? =
suspendCoroutine { cont ->
val callback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cont.resume(camera)
}


override fun onDisconnected(camera: CameraDevice) {
cont.resume(null)
}


override fun onError(camera: CameraDevice, error: Int) {
// assuming that we don't care about the error in this example
cont.resume(null)
}
}
openCamera(cameraId, callback, null)
}

Now, in your application code you can just do manager.openCamera(cameraId) and get a reference to CameraDevice if it was opened successfully or null if it was not.

Use suspendCancellableCoroutine instead of suspendCoroutine with proper exception handling

suspend fun CameraManager.openCamera(cameraId: String): CameraDevice? =
suspendCancellableCoroutine { cont ->
val callback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cont.resume(camera)
}


override fun onDisconnected(camera: CameraDevice) {
cont.resume(null)
}


override fun onError(camera: CameraDevice, error: Int) {
// Resume the coroutine by throwing an exception or resume with null
cont.resumeWithException(/* Insert a custom exception */)
}
}
openCamera(cameraId, callback, null)
}

It is preferable to always choose suspendCancellableCoroutine to handle cancellation of the coroutine scope, or to propagate cancellation from the underlying API. Source with other great examples