2010-07-20 10 views
13

Cela semble être une question de base, mais après avoir cherché pendant un moment et joué avec, je suis arrivé au point où de l'aide serait appréciée. Je souhaite que SensorEventListener soit exécuté dans un thread distinct de l'interface utilisateur, de sorte que les calculs qui doivent avoir lieu lorsque les événements arrivent ne ralentissent pas l'interface utilisateur.SensorEventListener dans thread séparé

Ma dernière tentative ressemble:

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

Dans de l'activité (ou de services) onCreate(), je crée un objet SensorThread et appeler sa méthode start(). Comme vous vous en doutez, le journal de débogage affiche l'entrée "RunTag" dans le nouveau thread. Mais "ListenerTag" de onSensorChanged() s'exécute dans le thread principal, même si son objet est instancié dans le nouveau thread. Comment puis-je changer cela?

+0

duplication possible de [Capteur d'acléromètre dans un fil séparé] (http://stackoverflow.com/questions/17513352/acclerometer-sensor-in-separate-thread) –

Répondre

6

Il semble que le SensorManager soit responsable de l'appel de la méthode onSensorChanged, et je ne pense pas que le fait que registerListener soit appelé dans ce thread séparé va faire une différence. La chose la plus facile à faire est probablement de rendre le retour onSensorChanged instantanément, en déléguant tous les poids lourds à un thread séparé. Ou peut-être à un ASyncTask, qui semble être la «bonne manière» officielle de faire de telles choses.

+0

Merci pour cette idée. Je viens du micro-monde 8 bits, donc je vais peut-être devoir ajuster ma réflexion. L'attribution de nouvelles tâches chaque fois que le capteur change (5-50x par seconde, en fonction du taux d'échantillonnage) semble être une perte. – Thinman

+2

Eh bien, peut-être que cela n'allouerait la tâche que dans certains cas. Par exemple, peut-être qu'il stocke la lecture du capteur en mémoire, puis vérifie dans la méthode onSensorChanged si la lecture a changé plus d'un certain seuil. Si c'est le cas, ALORS il démarre la ASyncTask.Je ne fais que commencer avec Android, donc je ne sais pas vraiment ce qui fonctionnera le mieux. – MatrixFrog

+0

OnSensorChanged devrait vraiment fonctionner dans ASyncTask - même si votre classe principale est un service d'arrière-plan (comme dans mon cas) il se peut que si vous ne revenez pas assez rapidement de la méthode, le prochain appel de SensorManager ne peut pas être fait ... – Radu

12

Vous pouvez recevoir un événement de capteur dans un fil d'arrière-plan. Au lieu de

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

vous pouvez le déclarer avec un gestionnaire se référant à un thread secondaire. La boucle d'exécution d'un thread ressemble à ceci:

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

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

+0

Ou utilisez android.os.HandlerThread et créez un gestionnaire: new Handler (yourHandlerThread.getLooper()) –

7

Un peu tard, mais si d'autres veulent encore le savoir, voici un bon moyen d'y parvenir. Comme toujours en multithreading, assurez-vous de savoir ce que vous faites et prenez le temps de le faire correctement, pour éviter ces erreurs bizarres. S'amuser!

membres de la classe:

private HandlerThread mSensorThread; 
private Handler mSensorHandler; 

en OnCreate ou lors de l'inscription:

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

Quand désinscription, font aussi:

mSensorThread.quitSafely(); 
+0

peut-être la meilleure réponse – Taranfx

+0

'Thread.MAX_PRIORITY' devrait être changé en' Process.THREAD_PRIORITY_MORE_FAVORABLE' comme recommandé dans [HandlerThread Android Developers] (https://developer.android.com/reference/android/os/HandlerThread.html#HandlerThread(java.lang.String,%20int)) "[...] La valeur fournie doit provenir du processus et non à partir de java.lang.Thread. " –

0

Créer gestionnaire pour le thread courant lorsque vous enregistrez votre auditeur et passez-le à l'auditeur en tant que troisième argument. Obtenez le gestionnaire du thread et enregistrez le programme d'écoute sur ce thread.

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

Par exemple:

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

espère que cela vous aiderait.

Questions connexes