2010-07-20 18 views
13

Esto parece una pregunta básica, pero después de buscar por un tiempo y jugar con él, llegué al punto en que se apreciaría algo de ayuda. Me gustaría tener un SensorEventListener ejecutado en un hilo separado de la interfaz de usuario, por lo que los cálculos que deben ocurrir cuando los eventos entran no ralentizarán la IU.SensorEventListener en un hilo separado

Mi último intento se ve así:

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

En la actividad (o de servicio) onCreate(), se crea un objeto SensorThread y llamar a su método start(). Como era de esperar, el registro de depuración muestra la entrada "RunTag" en el nuevo hilo. Pero el "ListenerTag" de onSensorChanged() se ejecuta en el hilo principal, aunque su objeto se instancia en el nuevo hilo. ¿Cómo cambio eso?

+0

posible duplicado de [Sensor Acclerometer en Hilo Separado] (http://stackoverflow.com/questions/17513352/acclerometer-sensor-in-separate-thread) –

Respuesta

6

Parece que SensorManager es realmente responsable de llamar al método onSensorChanged, y no creo que el hecho de que registerListener se invoque en este subproceso independiente va a hacer la diferencia. Lo más fácil es hacer que onSensorChanged regrese al instante, delegando todo el trabajo pesado en un hilo separado. O tal vez a una ASyncTask, que parece ser la "forma correcta" oficial de hacer tales cosas.

+0

Gracias por la idea. Vengo del micro mundo de 8 bits, así que tal vez deba ajustar mi forma de pensar. Asignar nuevas tareas cada vez que cambia el sensor (5-50x por segundo, dependiendo de la frecuencia de muestreo) parece un desperdicio. – Thinman

+2

Bueno, tal vez solo asignaría la tarea en ciertos casos. Por ejemplo, tal vez almacena la lectura del sensor en la memoria, y luego verifica en el método onSensorChanged si la lectura ha cambiado más que algún umbral. Si lo tiene, ENTONCES inicia ASyncTask.Aunque estoy empezando a usar Android, no sé qué funcionará mejor. – MatrixFrog

+0

OnSensorChanged realmente debería ejecutarse en ASyncTask, incluso si su clase principal es un servicio en segundo plano (como en mi caso) puede ser que si no regresa lo suficientemente rápido desde el método, la siguiente llamada de SensorManager no se puede hacer ... – Radu

12

Puede recibir un evento de sensor en una cadena de fondo. En lugar de

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

puede declararlo con un controlador que hace referencia a un hilo secundario. El bucle de ejecución de un hilo se ve así:

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

public void run() {... y Looper.prepare(); – Slackware

+0

O use android.os.HandlerThread y cree un controlador: new Handler (yourHandlerThread.getLooper()) –

7

Un poco tarde, pero si otros todavía quieren saber, aquí es una buena manera de lograr esto. Como siempre cuando multiples hilos, asegúrese de saber lo que está haciendo y tómese el tiempo para hacerlo bien, para evitar esos errores extraños. ¡Que te diviertas!

miembros de la Clase:

private HandlerThread mSensorThread; 
private Handler mSensorHandler; 

en OnCreate o cuando se registren:

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

Cuando la anulación del registro, también lo hacen:

mSensorThread.quitSafely(); 
+0

quizás la mejor respuesta – Taranfx

+0

'Thread.MAX_PRIORITY' debe cambiarse a' Process.THREAD_PRIORITY_MORE_FAVORABLE' como se recomienda en [HandlerThread Android Developers] (https://developer.android.com/reference/android/os/HandlerThread.html#HandlerThread(java.lang.String,%20int)) "[...] El valor proporcionado debe ser de Process y no de java.lang.Thread ". –

0

Crear controlador para el hilo actual en la que se está registrando su oyente y pasarlo al oyente como tercer argumento.

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; 

    } 
1

Obtenga el controlador del hilo y registre el detector en ese hilo. Por ejemplo:

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

espera que esto lo ayude.

Cuestiones relacionadas