有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java SensorEventListener不会使用unregisterListener()方法取消注册

我有一个非常简单的Android应用程序:在“活动”中,我有一个按钮,可以启动/停止OrientionListener。然而,在注销之后,在ddms中我仍然可以看到安卓的线程。硬件SensorManager$SensorThread](正在运行)

注册码:

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

和注销:

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

unregisterListener()方法确实会被执行,但是它不会经常杀死传感器线程,这会持续运行并耗尽电池电量。几个小时后,我的应用程序将耗电20-30%。这怎么可能?如何确保传感器未注册?我在logcat中没有得到任何异常或错误。我尝试在服务中运行侦听器-同样的事情


共 (6) 个答案

  1. # 1 楼答案

    我也有同样的问题。我检查了Android代码。 相关代码在SensorManager中。爪哇

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

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

    因此,线程似乎应该在不再有侦听器时终止

  2. # 2 楼答案

    在我的例子中,为了解决这个问题,我需要纠正我用来获取SensorManager的上下文。我在一家服务公司工作,我需要用这种方式获得SensorManager:

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

    因此,只要证明您使用的SensorManager方法是否正确即可

  3. # 3 楼答案

    可能是范围问题。注册和注销sensorEventListener和sensor时,请尝试记录它们的值。(.toString())以确保它们是相同的

  4. # 4 楼答案

    您没有显示足够的代码来确定答案,但是您的测试

    if (sensorManager != null && sensorEventListener != null)
    

    这根本不准确。也就是说,当您仍然注册为监听时,sensorManagersensorEventListener可能是null

  5. # 5 楼答案

    我也面临类似的问题

    停止传感器的解决方法

    我使用了一个静态布尔mIsSensorUpdateEnabled。当您想停止从传感器获取值时,将其设置为“false”。 在onSensorChanged()方法中,检查布尔变量的值,然后再次调用以注销传感器。这一次,它起作用了。传感器将被取消注册,您将不再使用SensorChanged回调

    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
        }
    }
    
  6. # 6 楼答案

    尝试将管理器设置为空

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

    然后在需要的时候再找经理。这应该使线程一致完成(在我的情况下就是这样)。我还没有找到任何解释这种行为的文件,但我很想听听