私は特定の例で一般的な質問があります:写真を撮るときに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()
}
...
どのようにそれを...エラー...よりlessいものに変換しますか? 3つ程度の関数で平均的なコールバックを取得し、プライマリフローをpromise-resultパスとして指定することでプロミスチェーンに変換することは可能ですか?もしそうなら、コルーチンを使用して非同期にする必要がありますか?
私は非同期と.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()
}
この特定のケースでは、一般的なアプローチを使用して、コールバックベースのAPIをsuspendCoroutine
関数を介して一時停止関数に変換できます。
_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
への参照を取得できます。
私はこの種のことに対して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 StateCallbackWrapper(val onOpened: (CameraDevice) -> (), val onClosed: (CameraDevice) ->()): CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpened(openedCameraDevice)
}
override fun onDisconnected(cameraDevice: CameraDevice) {
onClosed(cameraDevice)
}
}
個人的には、これらのようなものから始めて、その上にスレッドの違いを構築します。