androidandroid-sensorsintentservicecommonsware-cwacsensormanager

Delayed (timed) unregister sensor listener inside IntentService (WakefulIntentService)


I've implemented an IntentService which, using SensorManager, reads data from a heart rate sensor.

It gets periodically called using AlarmManager and a WakefulBroadcastReceiver and then, upon onSensorChanged, it updates Google Fit data by using Fitness History API, using the time of the onSensorChanged invocation as timestamp.

The IntentService, of course, implements a SensorEventListener and it's implemented as a WakefulIntentService using CommonsWare cwac-wakeful.

What's happening is that sensor reading task takes a very highly variable time and sometimes, onSensorChanged - which I guess works asynchronously once the sensor listener is registered - gets called even minutes later, when the IntentService instance which registered the sensor listener, has already ended and the listener listening (!) is a successive one.

This translates to a series of data readings overlapping and being inserted into Google Fit without any temporal order with respect to the original timed invocation of the IntentService measuring task.

Besides, this behaviour also causes an abnormal usage of the battery, since the heart rate sensor uses a couple of very bright leds and - unless unregistered - keeps staying active until, I guess, its hardware timeout.

I've tried to unregister the sensor listener inside the IntentService by calling a post delayed Runnable after a certain timeout (30 secs), but it's not working.

My questions are:

Is there a way, inside an IntentService or a WakefulIntentService to call the sensor unregisterListener after a certain delay preventing the thread to end, meanwhile? Or to clear the onSensorChanged queue somehow?

Alternatively: Is there a way to assign an univoque ID to a sensor listener at the moment of its registration? This way, inside the onSensorChanged, it would be possible to match the event against its originating IntentService invocation time and it could be - at least - possible to insert the readings in Google Fit with the right temporal order.

Thank you in advance.


Solution

  • I've implemented an IntentService which, using SensorManager, reads data from a heart rate sensor.

    IMHO, that is not a proper use of IntentService. IMHO, IntentService is designed for transaction bits of work: disk I/O, database I/O, Web service calls, etc. It is not designed for work of indefinite duration.

    The IntentService, of course, implements a SensorEventListener and it's implemented as a WakefulIntentService using CommonsWare cwac-wakeful.

    WakefulIntentService is not designed for doing work indefinitely.

    What's happening is that sensor reading task takes a very highly variable time and sometimes, onSensorChanged - which I guess works asynchronously once the sensor listener is registered - gets called even minutes later, when the IntentService instance which registered the sensor listener, has already ended and the listener listening (!) is a successive one.

    In general, there is no guarantee that you will get any sensor readings, as your process can terminate at any time once the service is destroyed.

    Is there a way, inside an IntentService or a WakefulIntentService to call the sensor unregisterListener after a certain delay preventing the thread to end, meanwhile?

    Not in any reliable fashion.

    Get rid of the WakefulIntentService. Use a regular Service. Register for sensor events. When you get the event(s) that you want, unregister the sensor listener and stopSelf() the service. Along the way, manage your own WakeLock.

    Or to clear the onSensorChanged queue somehow?

    Not that I am aware of.

    Is there a way to assign an univoque ID to a sensor listener at the moment of its registration?

    The listener object is already unique. Why would an ID make it more unique?

    That being said, you are welcome to put a field in your listener object that has whatever sort of unique value that you like.