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()
返回了两个不同的 SensorManager
s 并使其无法正常工作!谢谢!但我的问题是:应该在服务中使用哪一个?
伙计,我在这上面花了 2 个小时。谢谢【参考方案2】:
你没有显示足够的代码来确定,但也许你的测试
if (sensorManager != null && sensorEventListener != null)
根本不准确。也就是说,sensorManager
或 sensorEventListener
可能是 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() 方法取消注册的主要内容,如果未能解决你的问题,请参考以下文章