Android: Which thread calls .onSensorChanged?
Asked Answered
S

1

7

I've read a few discussions about which thread calls various callback methods, for example those associated with Sensors. Most claim that the UI thread calls the callbacks - even when a separate worker thread is involved. Are we CERTAIN about that?

Consider this scenario: A separate class implements Runnable and SensorListener. The UI thread (during onCreate) starts the runnable and then goes back to its other business. The now-independent worker thread, in its own class, then registers the SensorListener.

Note that the UI thread never has any interaction with SensorManager nor SensorListener. The only thread that ever touches anything to do with Sensor, and the only class and member methods that it ever knows about, is the worker thread and its class.

It's hard for me to imagine that the UI thread would be calling the callback in this situation. Yet the online discussions are pretty "confident". Anyone know for certain?

Thanks!

Shriner answered 16/7, 2013 at 16:18 Comment(1)
It probably is, but I suggest not relying on this, cause if it is not on documentation it may change.Composure
N
6

Are we CERTAIN about that?

Yes, though it depends on how you register the listener, and the behavior is not especially well-documented.

There are two registerListener() methods that take a SensorEventListener. One takes a Handler, the other does not. The latter one will use a Handler that is associated with the main application thread. If you wish to have the events delivered to a background thread, use a HandlerThread (which really should be called LooperThread, but they didn't ask me...), create a Handler in it, and use that Handler with registerListener().

Neuralgia answered 16/7, 2013 at 16:27 Comment(8)
The one I've been playing with is >>public boolean registerListener (SensorEventListener listener, Sensor sensor, int rate)<<. Its docs say nothing about a Handler. Are you saying that the callback method is put into the queue as a Runnable object? Otherwise I don't see how the UI thread would understand how to call the callback function if a Message appeared on its Handler.Shriner
@AndroidNewbie: You are welcome to review the source code for SensorManager and the concrete implementation SystemSensorManager at your leisure. Under the covers, Android currently creates one Handler per listener, using that Handler to dispatch events on the desired thread.Neuralgia
Thanks for the reference, I'll dig into it. When you say "on the DESIRED thread" (emphasis mine), does it compel that to be the UI thread? A Handler can be supported by non-UI threads too. This situation concerns me because it feels like there could be thread safety and synchronization problems if, despite everything being set up by a worker thread, the UI thread is then the one that invokes the callback. If that callback method is a member of some separate class, then you'll basically have two threads working within a common instance.Shriner
It's not obvious that thread sync would be necessary. Indeed, instancing a completely separate class that implements Runnable, and creating a dedicated thread for it, doesn't exactly shout that some other thread will have access to the private variables of the class but that's exactly what would happen!Shriner
@AndroidNewbie: "does it compel that to be the UI thread?" -- please re-read my answer. If you use the three-parameter registerSensorListener(), SystemSensorManager will create a Handler on the Looper of the main application thread, where that Looper is passed into the SystemSensorManager constructor by ContextImpl. You can tell this by reading the Android framework source code.Neuralgia
OK, I have read the source and agree with your info. Thank you very much for pointing me to this answer! However, it does beg one more question: If the interface between the SensorManager and a thread is based through a Handler, how is .onSensorChanged() called instead of the usual .handleMessage()? It's tempting to say that a Runnable is posted instead of a Message, but Runnable.run() does not match the calling parameters of onSensorChanged() because the latter takes a SensorEvent object.Shriner
@AndroidNewbie: "how is .onSensorChanged() called instead of the usual .handleMessage()?" -- handleMessage() is called. It is called on the SystemSensorManager-defined Handler, which calls onSensorChanged().Neuralgia
Ohhhhhh, I see it now. It's not using the UI's default Handler, it's using a dedicated Handler for each registered Listener. (There are comments in the docs about all Handlers on a thread getting all messages, but I'll leave that alone for now.) So SensorManager's internal implementation of handleMessage() knows to call onSensorChanged(), with the proper parameters, because it is specific to SensorManager. I think I've got it now. Thank you very much for your patience and assistance!Shriner

© 2022 - 2024 — McMap. All rights reserved.