android Kotlin协程的现有3函数回调

y53ybaqx  于 2023-02-27  发布在  Android
关注(0)|答案(3)|浏览(197)

我有一个一般性的问题,下面是一个具体的例子:我想使用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()
    }
    ...

我该如何将其转换为不那么难看的东西呢?***是否有可能将一个包含三个左右函数的普通回调函数,通过将主流指定为承诺-结果路径,将其转换为承诺-链?***如果有,我应该/应该使用协程使其异步吗?
我喜欢一些与异步和. waiting这将导致

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()
}
u4vypkhs

u4vypkhs1#

在这种特殊情况下,您可以使用一般方法通过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)
    }

现在,在应用程序代码中,您只需执行manager.openCamera(cameraId),如果成功打开,则获取对CameraDevice的引用,否则获取对null的引用。

yvgpqqbh

yvgpqqbh2#

使用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)
    }

最好总是选择suspendCancellableCoroutine来处理协程作用域的取消,或者从底层API传播取消。Source with other great examples

06odsfpq

06odsfpq3#

我用过两种方法来解决这种问题。
1:将接口 Package 在扩展中

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:创建一个具有更多功能接口的简单容器类:

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

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

就我个人而言,我会从这样的东西开始,然后在此基础上构建任何线程差异。

相关问题