现有的3函数回调Kotlin协同程序

Ben*_*n H 20 android kotlin kotlin-coroutines

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

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()
    }
    ...
Run Code Online (Sandbox Code Playgroud)

我怎么把它转换成......错误......不那么难看的东西? 是否可以使用三个左右的函数进行平均回调,并通过将主流指定为promise-result路径将其转换为promise链? 如果是这样,我应该/我是否应该使用协同程序使其异步?

我喜欢async和.await会产生的东西

manager.open(cameraId).await().createCaptureRequest()
Run Code Online (Sandbox Code Playgroud)

我试图通过以下内容来做到这一点,但是...我不认为我正在使用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()
}
Run Code Online (Sandbox Code Playgroud)

Rom*_*rov 61

在这种特殊情况下,您可以使用一般方法通过suspendCoroutine函数将基于回调的API转换为挂起函数:

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)
    }
Run Code Online (Sandbox Code Playgroud)

现在,在您的应用程序代码中,您可以执行manager.openCamera(cameraId)并获取CameraDevice对它是否已成功打开或null是否已成功打开的引用.

  • 在这种情况下你如何处理协程取消? (6认同)
  • 请注意,如果回调多次触发,例如在某些情况下旋转设备时,这将会崩溃 (5认同)
  • @Bolein95:通过使用“suspendCancellableCoroutine”来代替。 (3认同)
  • 您可以选择用异常表示错误并执行 `cont.resumeWithException(CameraException(error))` 或使用特殊结果类型表示错误并执行 `cont.resume(CameraErrorResult(error))`。 (2认同)
  • 这太完美了!我&lt;3个协程!:) (2认同)

小智 7

使用 suspendCancellableCoroutine 代替 suspendCoroutine 并进行适当的异常处理

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)
    }
Run Code Online (Sandbox Code Playgroud)

最好始终选择 suspendCancellableCoroutine 来处理协程范围的取消,或者从底层 API 传播取消。 来源与其他很好的例子