SensorEventListener в отдельной теме

Это похоже на основной вопрос, но после того, как вы некоторое время искали и играли с ним, я пришел к тому, что можно было бы оценить некоторую помощь. Я хотел бы, чтобы SensorEventListener запускался в отдельном потоке из пользовательского интерфейса, так что вычисления, которые должны возникать при поступлении событий, не замедляют работу пользовательского интерфейса.

Моя последняя попытка выглядит так:

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
        }
    }

В действии (или службе) onCreate() я создаю объект SensorThread и вызываю его метод start(). Как и следовало ожидать, в журнале отладки отображается запись "RunTag" в новом потоке. Но onSensorChanged() "ListenerTag" запущен в основном потоке, хотя его объект создается в новом потоке. Как мне это изменить?

Ответ 1

Вы можете получить событие датчика в фоновом потоке. Вместо

mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI );

вы можете объявить его обработчиком со ссылкой на вторичный поток. Пробег цикла потока выглядит следующим образом:

...
run {
    Looper.prepare;
    Handler handler = new Handler();
    ...
    mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI, handler );
    Looper.loop();
}
...

Ответ 2

Немного поздно, но если другие все еще хотят знать, вот хороший способ добиться этого. Как всегда, при многопоточности, убедитесь, что вы знаете, что делаете, и найдите время, чтобы это было правильно, чтобы избежать этих странных ошибок. Получайте удовольствие!

Члены класса:

private HandlerThread mSensorThread;
private Handler mSensorHandler;

в OnCreate или при регистрации:

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);

При отмене регистрации также выполните:

mSensorThread.quitSafely();

Ответ 3

Похоже, что SensorManager фактически отвечает за вызов метода onSensorChanged, и я не думаю, что тот факт, что registerListener вызывается в этом отдельном потоке, будет иметь значение. Самое легкое, что нужно сделать, - это, вероятно, сделать немедленное возвращение onSensorChanged, делегируя весь тяжелый подъем в отдельный поток. Или, возможно, к ASyncTask, который, кажется, является официальным "правильным способом" для выполнения таких вещей.

Ответ 4

Получить обработчик потока и зарегистрировать прослушиватель в этом потоке. Например:

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();
}

надеется, что это поможет вам.

Ответ 5

Создайте обработчик для текущего потока, в котором вы регистрируете слушателя и передаете его слушателю в качестве третьего аргумента.

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;

    }