Android的SensorManager无法有效取消注册侦听器

时间:2014-11-15 13:34:12

标签: android

我的应用会创建一个Service来覆盖onStartCommand以创建SensorManager并将SensorEventListener附加到其中一个传感器:

public class AccelerometerService extends Service {
    private SensorManager sensorManager;
    private Sensor sensor;
    private SensorEventListener activeListener; 
    // ...

    @Override
    public int onStartCommand(Intent intent, int flags, int startid) {
        // ...

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
        activeListener = new SensorEventListener() {
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {

            }

            @Override
            public void onSensorChanged(SensorEvent event) {
                Log.i("PluckLock", "" + event.values[0]);
            }
        };

        sensorManager.registerListener(activeListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);

        return START_STICKY;
    }

    // ...
}

完整代码可在GitHub上找到。

我想覆盖Service的{​​{1}}方法,并在其中杀死传感器:

onDestroy()

但是当我这样做时,实际上什么也没发生!我的sensorManager.unregisterListener(activeListener); 听众继续从加速计(或我的情况下的软件LINEAR_ACCELERATION传感器)接收正确的值。当然,问题在docs

中引用
  

始终确保禁用您不需要的传感器,尤其是在您的活动暂停时。如果不这样做,可能会在几个小时内耗尽电池电量。

只要屏幕实际解锁,我的应用只需要ping加速度计。我已经实现(并验证了)onSensorChanged()的正确功能,在手机被锁定时会破坏BroadcastReceiver,成功调用其Service方法。但是一旦我试图取消注册听众,实际上什么也没发生。

我发现其他一些人没有解决这个问题。

我只能假设它是一个API错误,并且一旦我开始从它们中获取数据,就没有好办法杀死这些传感器。我尝试将onDestroy()SensorManagerSensor设置为null,并尝试向管理器注册空传感器侦听器。这些都不会对民意调查产生任何影响。

我目前的“解决方法”对电池寿命几乎没有影响。我在类的定义中有一个私有布尔值,我将其设置为SensorEventListenertrue,具体取决于我是否需要传感器值。在我的false方法中,如果传感器侦听器应该处于非活动状态,我会立即onSensorChanged()。但到那时,为时已晚:在我能够设法离开return方法之前,操作系统执行的工作(获取传感器值)首当其冲,因此只要我的电池寿命仍然可怕服务正在运行。

我真正的问题是,除了一些奇迹真正的解决方案之外,我该怎么办才能停止获取传感器值?显然,取消注册传感器监听器不起作用点;即使将所有内容设置为null并销毁该服务也无效。但必须有一些方式向操作系统指示我的应用程序不再需要使用传感器值。有没有办法杀死我的整个应用程序,只有在手机解锁时重新启动它?也许这会让操作系统知道我的应用程序不再需要值了。真的,任何合法停止轮询传感器的解决方案,但给我一些重启它的方法,即使代码很丑,也会让我高兴。

我的项目的最低API级别为9。

2 个答案:

答案 0 :(得分:2)

我遇到了类似的问题。

解决方法,阻止传感器耗尽电池。

我使用了静态布尔值mIsSensorUpdateEnabled。如果要停止从传感器获取值,请将其设置为“false”。 在onSensorChanged()方法中,检查布尔变量的值,然后再调用以取消注册传感器。而这一次,它的确有效。传感器将被取消注册,您将不再获得onSensorChanged回调。

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

答案 1 :(得分:1)

我有同样的问题。最后,我通过将sensorManager对象设置为null来启用传感器读取。因此sensorManager无法注册任何监听器。当您想要读取传感器数据时,请调用startRegister方法来定义sensorManager对象和侦听器。这是我的代码:

public class SensorReadingClass implements SensorEventListener {

    public SensorReadingClass(Service c){
        this.mContext=c;
        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager != null) {
            // list available sensors and power consumption
            List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        } else {
            if(DBG) Log.e(TAG, "Could not get SensorManager instance");
        }
    }

    public float getHeartRate(){
        Log.d(TAG,"Heart Rate return value: " + heartRate);
        return heartRate;
    }

    public void startSensorListeners() {
        Log.d(TAG, "startSensorListeners");

        if(mSensorManager==null){
            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        }

        readSensors=true;

        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE), SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL);

        Log.d(TAG, "Sensor started: " + mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL));

    }

    public void stopSensorListeners() {
        Log.d(TAG, "stopSensorListeners");

        if(mSensorManager!=null) {
            mSensorManager.unregisterListener(this);
            mSensorManager=null;
        }

        Log.d(TAG, "Sensor stoppped: " + mSensorManager);
        readSensors=false;

    }

    @Override
    public void onSensorChanged(SensorEvent event) {

            String key = event.sensor.getName();
            float values = event.values[0];
            Sensor sensor = event.sensor;

            if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                accellerometerEvent++;                  // this is event counts when sensor changes, this counts all the events changings. It shouldnt be necessary though
                accellerometerSensor = values + " " + event.values[1] + " " + event.values[2] + " " + accellerometerEvent; // This is the string for value and seen event count.

            }

            if (sensor.getType() == Sensor.TYPE_HEART_RATE) {
                heartRateEvent++;
                heartRateSensor = values + " " + heartRateEvent;
                heartRate = values;

            }

            if (sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
                stepCounterEvent++;
                stepCounterSensor = values + " " + stepCounterEvent;

            }

            if (sensor.getType() == Sensor.TYPE_GYROSCOPE) {
                gyroscopeEvent++;
                try {
                    gyroscopeSensor = values + " " + event.values[1] + " " + event.values[2] + " " + gyroscopeEvent;
                } catch (Exception e) {
                }

            }

            lastTime = System.currentTimeMillis();
        }

    @Override
    // since we will always capture the data whether it changes or not, we don't need this method
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        return;
    }

}