对 Kotlin 协程的现有 3 函数回调
Existing 3-function callback to 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()
}
...
我如何将其转换为不那么丑陋的东西? 是否可以采用三个左右函数的平均回调,并通过将主要流程指定为承诺-结果路径将其转变为承诺链? 如果是这样,should/do 我使用协程使其异步?
我喜欢带有 async 和 .await 的东西,它会导致
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()
}
对于这类事情,我使用了 2 种解决方案。
1:将接口包装在扩展中
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 具有更实用的界面:
class StateCallbackWrapper(val onOpened: (CameraDevice) -> (), val onClosed: (CameraDevice) ->()): CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpened(openedCameraDevice)
}
override fun onDisconnected(cameraDevice: CameraDevice) {
onClosed(cameraDevice)
}
}
就我个人而言,我会从这些东西开始,然后在此基础上构建任何线程差异。
在这种特殊情况下,您可以使用通用方法通过 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
(如果未成功打开)。
使用 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
我有一个带有具体示例的一般性问题:我想在 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()
}
...
我如何将其转换为不那么丑陋的东西? 是否可以采用三个左右函数的平均回调,并通过将主要流程指定为承诺-结果路径将其转变为承诺链? 如果是这样,should/do 我使用协程使其异步?
我喜欢带有 async 和 .await 的东西,它会导致
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()
}
对于这类事情,我使用了 2 种解决方案。
1:将接口包装在扩展中
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 具有更实用的界面:
class StateCallbackWrapper(val onOpened: (CameraDevice) -> (), val onClosed: (CameraDevice) ->()): CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpened(openedCameraDevice)
}
override fun onDisconnected(cameraDevice: CameraDevice) {
onClosed(cameraDevice)
}
}
就我个人而言,我会从这些东西开始,然后在此基础上构建任何线程差异。
在这种特殊情况下,您可以使用通用方法通过 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
(如果未成功打开)。
使用 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