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.op
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.
I've used 2 solutions for this type of thing.
1: wrap the interface in an extension
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: Make a simple container class with a more functional interface:
class StateCallbackWrapper(val onOpened: (CameraDevice) -> (), val onClosed: (CameraDevice) ->()): CameraDevice.StateCallback() {
override fun onOpened(openedCameraDevice: CameraDevice) {
onOpened(openedCameraDevice)
}
override fun onDisconnected(cameraDevice: CameraDevice) {
onClosed(cameraDevice)
}
}
Personally I would start with something like these, and then build whatever threading differences on top of that.