2011-08-02 5 views
27

Mam bardzo prostą aplikację na Androida: w działaniu mam przycisk i uruchamiam/zatrzymuję narzędzie OrientationListener. Jednak po wyrejestrowaniu go, w ddms nadal widzę wątek android.hardware.SensorManager $ SensorThread] (Running).SensorEventListener nie zostanie wyrejestrowany za pomocą metody unregisterListener()

Kod rejestracyjny:

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION); 
if (sensors.size() > 0) 
{ 
    sensor = sensors.get(0); 
    running = sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_FASTEST); 
} 

i wyrejestrowania:

try 
{ 
    if (sensorManager != null && sensorEventListener != null) 
    { 
     sensorManager.unregisterListener(sensorEventListener,sensor); 
     running = false; 
    } 
} 
catch (Exception e) 
{ 
    Log.w(TAG, e.getMessage()); 
} 

Sposób unregisterListener() nie zostanie wykonany, jednak nie zabija wątku czujniki bardzo często, co utrzymuje prowadzenie oraz odprowadzanie bateria. Po kilku godzinach moja aplikacja jest wymieniona z 20-30% wyczerpaniem baterii. Jak to możliwe? Jak mogę się upewnić, że czujnik zostanie wyrejestrowany? Nie otrzymuję żadnych wyjątków ani żadnych błędów w kodzie logowania. Próbowałem uruchomić słuchacza w Serwisie - to samo.

+0

Miałem podobny problem, rozwiązać go tutaj http://stackoverflow.com/questions/16504474/ wątek z Androidem - nie można wyrejestrować - sensoreventlistener [1]: http://stackoverflow.com/questions/16504474/android-thread-cannot-unregister-sensoreventlistener – tricknology

Odpowiedz

1

Może to być problem z zakresem. Spróbuj zarejestrować wartości czujnika sensorEventListener i czujnika podczas rejestracji i wyrejestrowania. (.toString()), aby upewnić się, że są takie same.

+0

To nie to. Są dokładnie takie same. – jacek

+0

To była kluczowa rada. Dodanie dobrego DEBUGA pomogło mi w pościgu w kilku kwestiach, 2 duże problemy to: 1) Właściwa rejestracja/wyrejestrowanie (w ramach kontekstu), 2) Wdrożenie odpowiednich kontroli boolowskich w miejscach takich jak rejestracja, wyrejestrowanie i onSensorChanged(). 3) Zaimplementowałem rejestrację w wątku tła (uwaga!). –

2

Spróbuj ustawić menedżera null

sensorManager.unregisterListener(sensorEventListener,sensor); 
sensorManager = null; 

a następnie uzyskać menedżera ponownie, gdy jest to potrzebne. To powinno sprawić, że nitka zakończy się konsekwentnie (tak było w moim przypadku). Nie znalazłem żadnej dokumentacji wyjaśniającej to zachowanie, ale byłbym zainteresowany usłyszeniem o tym.

+0

Próbowałem również - nic się nie zmienia. – jacek

+0

Postępując zgodnie z tą radą (i innymi osobami w tym poście SO) zrobiłem dla mnie. To była część ogólnego problemu. Ponadto: 1) Wprowadziłem również odpowiednie kontrole boolowskie w miejscach takich jak rejestracja, wyrejestrowanie i onSensorChanged(). 2) Zachowany właściwy kontekst. –

2

Mam ten sam problem. Sprawdziłem kod Androida. Odpowiedni kod jest w SensorManager.java

private void unregisterListener(Object listener) { 
    if (listener == null) { 
     return; 
    } 

    synchronized (sListeners) { 
     final int size = sListeners.size(); 
     for (int i=0 ; i<size ; i++) { 
      ListenerDelegate l = sListeners.get(i); 
      if (l.getListener() == listener) { 
       sListeners.remove(i); 
       // disable all sensors for this listener 
       for (Sensor sensor : l.getSensors()) { 
        disableSensorLocked(sensor); 
       } 
       break; 
      } 
     } 
    } 
} 

i

 public void run() { 
      //Log.d(TAG, "entering main sensor thread"); 
      final float[] values = new float[3]; 
      final int[] status = new int[1]; 
      final long timestamp[] = new long[1]; 
      Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 

      if (!open()) { 
       return; 
      } 

      synchronized (this) { 
       // we've open the driver, we're ready to open the sensors 
       mSensorsReady = true; 
       this.notify(); 
      } 

      while (true) { 
       // wait for an event 
       final int sensor = sensors_data_poll(sQueue, values, status, timestamp); 

       int accuracy = status[0]; 
       synchronized (sListeners) { 
        if (sensor == -1 || sListeners.isEmpty()) { 
         // we lost the connection to the event stream. this happens 
         // when the last listener is removed or if there is an error 
         if (sensor == -1 && !sListeners.isEmpty()) { 
          // log a warning in case of abnormal termination 
          Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor); 
         } 
         // we have no more listeners or polling failed, terminate the thread 
         sensors_destroy_queue(sQueue); 
         sQueue = 0; 
         mThread = null; 
         break; 
        } 
        final Sensor sensorObject = sHandleToSensor.get(sensor); 
        if (sensorObject != null) { 
         // report the sensor event to all listeners that 
         // care about it. 
         final int size = sListeners.size(); 
         for (int i=0 ; i<size ; i++) { 
          ListenerDelegate listener = sListeners.get(i); 
          if (listener.hasSensor(sensorObject)) { 
           // this is asynchronous (okay to call 
           // with sListeners lock held). 
           listener.onSensorChangedLocked(sensorObject, 
             values, timestamp, accuracy); 
          } 
         } 
        } 
       } 
      } 
      //Log.d(TAG, "exiting main sensor thread"); 
     } 
    } 
} 

Tak wygląda nitka powinna zostać rozwiązana, gdy nie ma już więcej słuchaczy

+0

Mam również ten sam problem http://stackoverflow.com/questions/16504474/android-thread-cannot-unregister-sensoreventlistener – tricknology

3

Nie wystarczy pokazać kod, aby powiedzieć na pewno, ale może twój test jest prosty i po prostu muszę przetestować. nie są dokładne. To znaczy, sensorManager lub może być null, gdy nadal jesteś zarejestrowany jako słuchający.

+0

Dobra uwaga tutaj. To mnie wyrzuciło - zwłaszcza przy rejestrowaniu czujników w wątku tła (bez odpowiedniego kontekstu). –

2

Napotkałem podobny problem.

Obejście problemu zatrzymania czujnika.

Użyłem statycznej wartości boolowskiej mIsSensorUpdateEnabled. Ustaw go na "false", gdy chcesz przestać otrzymywać wartości z czujników. W metodzie onSensorChanged() sprawdź wartość zmiennej boolean i ponownie wykonaj wywołanie, aby wyrejestrować czujniki. I tym razem działa. Czujniki zostaną wyrejestrowane i nie będzie można uzyskać połączenia zwrotnegoSensorChanged.

public class MainActivity extends Activity implements SensorEventListener { 
    private static boolean mIsSensorUpdateEnabled = false; 
    private SensorManager mSensorManager; 
    private Sensor mAccelerometer; 

    @override 
    protected void onCreate(){ 
     mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 
    } 

    private startSensors(){ 
     mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
     int delay = 100000; //in microseconds equivalent to 0.1 sec 
     mSensorManager.registerListener(this, 
       mAccelerometer, 
       delay 
     ); 
     mIsSensorUpdateEnabled =true; 
    } 

    private stopSensors(){ 
     mSensorManager.unregisterListener(this, mAccelerometer); 
     mIsSensorUpdateEnabled =false; 
    } 


    @Override 
    public void onSensorChanged(SensorEvent event) { 
     if (!mIsSensorUpdateEnabled) { 
      stopSensors(); 
      Log.e("SensorMM", "SensorUpdate disabled. returning"); 
      return; 
     } 
     //Do other work with sensor data 
    } 
} 
+0

To był klucz do rozwiązania mojego problemu. Odnoś się do innych moich komentarzy w tym poście SO. –

2

W moim przypadku, aby rozwiązać ten problem, musiałem poprawić kontekst, którego używałem do uzyskania SensorManagera.Byłem wewnątrz Service, a ja potrzebowałem dostać SensorManager ten sposób:

SensorManager sensorManager = (SensorManager) getApplicationContext().getSystemService(SENSOR_SERVICE); 

Tak, tylko poświadczyć jeśli otrzymujesz SensorManager właściwy sposób.

+1

Solidna rada tutaj! To był jeden z 3 moich problemów. Przeczytaj inne komentarze, które poczyniłem w tym poście. –

+0

Mój problem też, 'applicationContext.getSystemService()' i 'Service.getSystemService()' zwróciły dwa różne 'SensorManager's i sprawiły, że nie działa! DZIĘKI! Ale moje pytanie: który z nich powinien być używany w ramach usługi? –

0
//Declaration of SensorManager 
private SensorManager sensorManager; 
private Sensor mAccelerometer; 
private SensorEventListener sensorEventListener; 

onCreate wezwanie do

try { 
     sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); 
     sensorManager.registerListener(sensorEventListener=new SensorEventListener() { 
      int orientation = -1; 

      @Override 
      public void onSensorChanged(SensorEvent event) { 
       if (event.values[1] < 6.5 && event.values[1] > -6.5) { 
        if (orientation != 1) { 
         Log.d("Sensor", "Landscape"); 
        } 
        orientation = 1; 
       } else { 
        if (orientation != 0) { 
         Log.d("Sensor", "Portrait"); 


        } 
        orientation = 0; 
       } 
      } 

      @Override 
      public void onAccuracyChanged(Sensor sensor, int accuracy) { 
      } 
     }, 
       mAccelerometer=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

Zadzwoń, aby na Destroy

if (sensorManager != null && mAccelerometer != null) 
{ 
    sensorManager.unregisterListener(sensorEventListener, mAccelerometer); sensorManager = null; 
} 
+0

Proszę sprawdzić powyżej anser –

+0

Dodaj wyjaśnienie z odpowiedzią na pytanie, w jaki sposób ta odpowiedź pomoże OP w ustalaniu bieżącego problemu –

Powiązane problemy