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

Posted

技术标签:

【中文标题】SensorEventListener 不会使用 unregisterListener() 方法取消注册【英文标题】:SensorEventListener doesn't get unregistered with unregisterListener() method 【发布时间】:2011-10-18 16:10:51 【问题描述】:

我有一个非常简单的 android 应用程序:在活动中我有一个按钮,我启动/停止 OrientationListener。但是,注销后,在 ddms 中我仍然可以看到线程 android.hardware.SensorManager$SensorThread] (Running)

注册码:

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 中没有任何异常或任何错误。我尝试在服务中运行监听器 - 同样的事情。

【问题讨论】:

我也遇到了类似的问题,在这里解决了***.com/questions/16504474/…[1]:***.com/questions/16504474/… 【参考方案1】:

就我而言,为了解决这个问题,我需要更正用于获取 SensorManager 的上下文。我在一个服务中,我需要以这种方式获取 SensorManager:

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

因此,只需证明您获取 SensorManager 的方式是否正确。

【讨论】:

这里有可靠的建议!这是我的 3 个问题中的 1 个。参考我在这篇文章中制作的其他 cmets。 我的问题也是,applicationContext.getSystemService()Service.getSystemService() 返回了两个不同的 SensorManagers 并使其无法正常工作!谢谢!但我的问题是:应该在服务中使用哪一个? 伙计,我在这上面花了 2 个小时。谢谢【参考方案2】:

你没有显示足够的代码来确定,但也许你的测试

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

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

【讨论】:

好点在这里。这让我大吃一惊——尤其是在后台线程中注册传感器时(没有适当的上下文)。【参考方案3】:

尝试将管理器设置为 null

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

然后在需要时再次获取经理。这应该使线程始终如一地完成(在我的情况下确实如此)。我没有找到任何解释这种行为的文档,但我有兴趣了解它。

【讨论】:

遵循此建议(以及此 SO 帖子中的其他建议)对我有用。这是整个问题的一部分。我还: 1) 我还在注册、注销和 onSensorChanged() 等地方实施了适当的布尔检查。 2)保持适当的上下文。【参考方案4】:

我也有同样的问题。我检查了Android代码。 相关代码在 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;
            
        
    

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

所以看起来线程应该在没有监听器的时候终止

【讨论】:

我也有同样的问题***.com/questions/16504474/…【参考方案5】:

我遇到了类似的问题。

停止传感器的解决方法。

我使用了静态布尔值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
    

【讨论】:

这是解决我的问题的关键。在这篇 SO 帖子中参考我的其他 cmets。【参考方案6】:

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

【讨论】:

不是这样的。它们完全相同。 这是关键建议。添加好的调试帮助我解决了几个问题,两个大问题是:1)正确注册/注销(在上下文中),2)在注册、注销和 onSensorChanged()等地方实施正确的布尔检查。 3)我在后台线程中实现了注册(当心!)。【参考方案7】:
//Declaration of SensorManager
private SensorManager sensorManager;
private Sensor mAccelerometer;
private SensorEventListener sensorEventListener;

onCreate 调用到

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

请调用销毁

if (sensorManager != null && mAccelerometer != null) 
 
    sensorManager.unregisterListener(sensorEventListener, mAccelerometer); sensorManager = null; 

【讨论】:

请查看上面的分析器 添加一些解释,说明此答案如何帮助 OP 解决当前问题

以上是关于SensorEventListener 不会使用 unregisterListener() 方法取消注册的主要内容,如果未能解决你的问题,请参考以下文章

Android 光线传感器的调用

传感器

SensorService小结

震动事件侦听器

Android 摇一摇监听实现

使用摇一摇功能开启不同的活动