https://kotlinlang.org logo
Title
k

kotlinforandroid

06/21/2022, 11:50 AM
I want to periodically read the value of the stepcounter sensor using a
androidx.work.Worker
. However, reading the value requires me to register a callback. How do I make my worker wait for the callback to return once without using a busy-loop? Is there a builtin way?
JobService
has a dedicated
finishJob
method that one could call from the callback.
androidx.work
seems to not have this
class MyWorker(sm: SensorManager, sensor: Sensor, context: Context, params: WorkerParameter): Worker(context, params) {
    private flag: Boolean = false

    override fun doWork(): Result {
        sm.registerListener(object : SensorEventListener {
            override fun onSensorEvent(e: SensorEvent) {
                flag = true
                // use value...
            }
        }, sensor, TIMEFRAME_FASTEST)
        
        while (!flag) {  }
        return Result.success()
    }
}
:not-kotlin: 1
a

Adam Powell

06/21/2022, 1:28 PM
If you use a
CoroutineWorker
you can use suspending to do it
k

kotlinforandroid

06/21/2022, 1:48 PM
@Adam Powell I don't see how that can be useful given that the `registerListener`` method isn't suspend and I cannot wait for a result in a
CoroutineContext
. Could you further elaborate on your suggestion? Maybe showing a code snippet on how you would use
CoroutineWorker
.
c

Casey Brooks

06/21/2022, 2:37 PM
Here’s the documentation for `CoroutineWorker`: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/coroutineworker And
suspendCancellableCoroutine
is the bridge between the callback-based
registerListener
and coroutines So you’d end up with a
doWork()
function like this:
override suspend fun doWork(): Result {
    return suspendCancellableCoroutine { continuation ->
        sm.registerListener(object : SensorEventListener {
            override fun onSensorEvent(e: SensorEvent) {
                // use value...
                continuation.resume(Result.success())
            }
        }, sensor, TIMEFRAME_FASTEST)
    }
}
1
k

kotlinforandroid

06/21/2022, 3:42 PM
I wasnt aware of suspendCancellableCoroutine, thank you!
a

Adam Powell

06/21/2022, 7:24 PM
or build it using a
callbackFlow {}
or similar. I'd assume that the above snippet verbatim with
suspendCancellableCoroutine
would still leave the listener registered; whatever solution you go with should account for cleaning that up
1
g

gildor

06/22/2022, 3:42 AM
Yes, example above doesn’t handle cancellation and leaks and also will throw exception on second sensor event (because it already returned) It’s better to use Flow anyway to wrap callbacks which could be called multiple times and then just do myFlow.first() if you wait for only 1 event
1