Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Existing 3-function callback to Kotlin Coroutines

I have a general question with a specific example: I'd like to use Kotlin coroutine magic instead of callback hell in Android when taking a picture.

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

How would I convert that to something less ugly? Is it possible to take an average callback with three or so functions, and turn it into a promise-chain by designating the primary flow as the promise-result path? And if so, should/do I use coroutines to make it async?

I'd love something with async and .await that would result in

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

I'm trying to do it through something like the following, but I don't think I'm using CompletableDeferred right!

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() } 
like image 548
Benjamin H Avatar asked Jan 31 '18 23:01

Benjamin H


People also ask

Are Kotlin coroutines concurrent?

Kotlin coroutines & structured concurrencyIn Kotlin, we can create coroutines using builders such as launch and async , which return a Job instance. This Job may further contain nested coroutine builders that create children Job instances that are computed concurrently.

Do coroutines run concurrently?

Coroutines can be executed concurrently using a multi-threaded dispatcher like the Dispatchers.


1 Answers

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.

like image 62
Roman Elizarov Avatar answered Oct 01 '22 12:10

Roman Elizarov