java - studio - SensorEventListener no se anula el registro con el método unregisterListener()
sensormanager getinclination (7)
Tengo una aplicación para Android muy simple: en la actividad tengo un botón y comienzo / detengo el Detector de Orientación. Sin embargo, después de anular el registro, en ddms todavía puedo ver el hilo android.hardware.SensorManager $ SensorThread] (En ejecución) .
El código de registro:
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);
}
y anulación del registro:
try
{
if (sensorManager != null && sensorEventListener != null)
{
sensorManager.unregisterListener(sensorEventListener,sensor);
running = false;
}
}
catch (Exception e)
{
Log.w(TAG, e.getMessage());
}
El método unregisterListener()
se ejecuta, sin embargo, no mata el hilo de los sensores muy a menudo, lo que sigue funcionando y agotando la batería. Después de unas horas, mi aplicación aparece con un 20-30% de descarga de la batería. ¿Cómo es eso posible? ¿Cómo puedo asegurarme de que el sensor quede sin registrar? No obtengo ninguna excepción ni error en el logcat. Intenté ejecutar el oyente en el Servicio - lo mismo.
En mi caso, para resolver este problema necesitaba corregir el contexto que estaba usando para obtener SensorManager. Estaba dentro de un Servicio, y necesitaba obtener el SensorManager de esta manera:
SensorManager sensorManager = (SensorManager) getApplicationContext().getSystemService(SENSOR_SERVICE);
Entonces, solo certifique si está obteniendo el SensorManager de la manera correcta.
Estoy teniendo el mismo problema. Revisé el código de Android. El código relevante está en 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;
}
}
}
}
y
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");
}
}
}
Así que parece que el hilo debe terminar cuando ya no hay oyentes
Intenta establecer el administrador en nulo
sensorManager.unregisterListener(sensorEventListener,sensor);
sensorManager = null;
y luego volver a obtener el administrador cuando lo necesite. Esto debería hacer que el hilo termine consistentemente (lo hizo en mi caso). No he encontrado ninguna documentación que explique este comportamiento, pero me interesaría saberlo.
Me enfrenté a un problema similar.
Solución para detener el sensor.
Utilicé un mIsSensorUpdateEnabled
booleano mIsSensorUpdateEnabled
. Establézcalo en ''falso'' cuando desee dejar de obtener valores de los sensores. Y en el método onSensorChanged (), verifique el valor de la variable booleana y nuevamente haga una llamada para cancelar el registro de los sensores. Y esta vez, funciona. Los sensores no se registrarán y ya no obtendrá la devolución de llamada en SensChanged.
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
}
}
No muestra el código suficiente para decirlo con seguridad, pero tal vez su prueba
if (sensorManager != null && sensorEventListener != null)
simplemente no es exacto. Es decir, sensorManager
o sensorEventListener
puede ser null
cuando aún está registrado como escucha.
Podría ser un problema con el alcance. Intente registrar los valores de sensorEventListener y sensor cuando se registre y anule el registro. (.toString ()) para asegurarse de que sean iguales.
//Declaration of SensorManager
private SensorManager sensorManager;
private Sensor mAccelerometer;
private SensorEventListener sensorEventListener;
onCreate call To
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();
}
Por favor llame al para destruir
if (sensorManager != null && mAccelerometer != null)
{
sensorManager.unregisterListener(sensorEventListener, mAccelerometer); sensorManager = null;
}