Reputation: 191
This seems like a basic question, but after searching for a while and playing with it, I've come to the point where some help would be appreciated. I would like to have a SensorEventListener run in a separate thread from the UI, so that computations that need to occur when events come in won't slow down the UI.
My latest attempt looks like:
class SensorThread extends Thread {
SensorManager mSensorManager;
Sensor mSensor;
public void run() {
Log.d( "RunTag", Thread.currentThread().getName() ); // To display thread
mSensorManager = (SensorManager)getSystemService( SENSOR_SERVICE );
mSensor = mSensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER );
MySensorListener msl = new MySensorListener();
mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI );
}
private class MySensorListener implements SensorEventListener {
public void onAccuracyChanged (Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent sensorEvent) {
Log.d( "ListenerTag", Thread.currentThread().getName() ); // To display thread
}
}
In the activity's (or service's) onCreate(), I create a SensorThread object and call its start() method. As you would expect, the debug log shows the "RunTag" entry in the new thread. But onSensorChanged()'s "ListenerTag" is running in the main thread, even though its object is instantiated in the new thread. How do I change that?
Upvotes: 19
Views: 14749
Reputation: 1155
Get the handler of the thread and register the listener on that thread. For example:
public void run() {
Sensor sensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
Looper.prepare();
Handler gHandler = new Handler();
this.sensorManager.registerListener(gravitySensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, gHandler);
Looper.loop();
}
hopes this would help you.
Upvotes: 1
Reputation:
Create handler for the current thread where you are registering your listener and pass it to the listener as third argument.
public void run() {
Log.d( "RunTag", Thread.currentThread().getName() ); // To display thread
mSensorManager = (SensorManager)getSystemService( SENSOR_SERVICE );
mSensor = mSensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER );
MySensorListener msl = new MySensorListener();
Looper.perpare;
Handler hndlr = new Handler();
mSensorManager.registerListener(msl, mSensor,
SensorManager.SENSOR_DELAY_UI, hndlr);
Looper.loop;
}
Upvotes: 0
Reputation: 1624
A little late, but if others still want to know, here is a good way to achieve this. As always when multithreading, make sure you know what you are doing and take the time to so it right, to avoid those weird errors. Have fun!
Class members:
private HandlerThread mSensorThread;
private Handler mSensorHandler;
in OnCreate or when registering:
mSensorThread = new HandlerThread("Sensor thread", Thread.MAX_PRIORITY);
mSensorThread.start();
mSensorHandler = new Handler(mSensorThread.getLooper()) //Blocks until looper is prepared, which is fairly quick
yourSensorManager.registerListener(yourListener, yourSensor, interval, mSensorHandler);
When unregistering, also do:
mSensorThread.quitSafely();
Upvotes: 24
Reputation: 2506
You can receive sensor event in a background thread. Instead of
mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI );
you can declare it with a handler referring to a secondary thread. The run loop of a thread looks like this:
...
run {
Looper.prepare;
Handler handler = new Handler();
...
mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI, handler );
Looper.loop();
}
...
Upvotes: 13
Reputation: 22126
It looks like the SensorManager is actually responsible for calling the onSensorChanged method, and I don't think the fact that registerListener is called in this separate thread is going to make any difference. The easiest thing to do is probably to make onSensorChanged return instantly, by delegating all the heavy lifting to a separate thread. Or perhaps to an ASyncTask, which seems to be the official "right way" of doing such things.
Upvotes: 6