2010-07-20 39 views
13

这似乎是一个基本问题,但经过一段时间的寻找并使用它后,我已经到了希望得到一些帮助的地步。我想让一个SensorEventListener在用户界面的一个单独线程中运行,以便事件进入时需要发生的计算不会减慢用户界面的速度。SensorEventListener在单独的线程中

我的最新尝试是这样的:

class SensorThread extends Thread { 
    SensorManager mSensorManager; 
    Sensor mSensor; 

    public void run() { 
     Log.d("RunTag", Thread.currentThread().getName()); // To display thread 
     mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE ); 
     mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
     MySensorListener msl = new MySensorListener(); 
     mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI); 
    } 

    private class MySensorListener implements SensorEventListener { 
     public void onAccuracyChanged (Sensor sensor, int accuracy) {} 
     public void onSensorChanged(SensorEvent sensorEvent) { 
      Log.d("ListenerTag", Thread.currentThread().getName()); // To display thread 
     } 
    } 

在活动中(或服务的)的onCreate(),我创建了一个SensorThread对象,并调用它的start()方法。正如您所期望的那样,调试日志会在新线程中显示“RunTag”条目。但是onSensorChanged()的“ListenerTag”正在主线程中运行,即使它的对象在新线程中实例化了。我该如何改变它?

+0

[单独线程中的Acclerometer传感器]的可能重复(http://stackoverflow.com/questions/17513352/acclerometer-sensor-in-separate-thread) – 2013-10-03 09:52:50

回答

6

它看起来像SensorManager实际上负责调用onSensorChanged方法,并且我不认为在这个单独的线程中调用registerListener的事实将会产生任何影响。最简单的做法可能是让onSensorChanged立即返回,方法是将所有繁重的任务委托给一个单独的线程。或者也许是一个ASyncTask,这似乎是做这种事情的官方“正确方法”。

+0

感谢您的想法。我来自8位微型世界,所以我可能需要调整我的想法。每当传感器发生变化时(每秒5-50次,取决于采样速率),分配新任务似乎是一种浪费。 – Thinman 2010-07-20 20:45:06

+2

好吧,也许它只会在某些情况下分配任务。例如,也许它将传感器读数存储在内存中,然后检查onSensorChanged方法读数是否已经改变超过某个阈值。如果有,那么它启动ASyncTask。我真的刚刚开始使用Android,所以我不知道什么会最好。 – MatrixFrog 2010-07-21 04:28:26

+0

OnSensorChanged应的AsyncTask真正运行 - 即使你的主类是一个后台服务(如在我的情况),这可能是因为,如果没有足够快的速度从方法返回,到SensorManager下次调用不能进行... – Radu 2012-08-16 17:21:25

12

您可以在后台线程中接收传感器事件。而不是

mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI); 

您可以使用指向辅助线程的处理程序声明它。一个线程的运行循环是这样的:

... 
run { 
    Looper.prepare; 
    Handler handler = new Handler(); 
    ... 
    mSensorManager.registerListener(msl, mSensor, SensorManager.SENSOR_DELAY_UI, handler); 
    Looper.loop(); 
} 
... 
+0

public void run(){...和Looper.prepare(); – Slackware 2014-01-06 18:01:52

+0

或者使用android.os.HandlerThread并创建一个Handler:new Handler(yourHandlerThread.getLooper()) – 2016-01-15 09:00:42

7

一点点,但是如果别人还是想知道,这里是实现这一目标的好方法。与多线程一样,确保你知道自己在做什么,并花时间做正确的事情,以避免那些奇怪的错误。玩的开心!

类成员:

private HandlerThread mSensorThread; 
private Handler mSensorHandler; 
在OnCreate中

或注册时:

mSensorThread = new HandlerThread("Sensor thread", Thread.MAX_PRIORITY); 
mSensorThread.start(); 
mSensorHandler = new Handler(mSensorThread.getLooper()) //Blocks until looper is prepared, which is fairly quick 
yourSensorManager.registerListener(yourListener, yourSensor, interval, mSensorHandler); 

注销时,也这样做:

mSensorThread.quitSafely(); 
+0

也许最好的答案 – Taranfx 2017-03-13 18:55:32

+0

[Thread.MAX_PRIORITY]应该改成'Process.THREAD_PRIORITY_MORE_FAVORABLE',如[HandlerThread Android Developers] (https://developer.android.com/reference/android/os/HandlerThread.html#HandlerThread(java.lang.String,%20int)) “[...]提供的值必须是从过程,而不是来自java.lang.Thread。“ – 2017-12-17 18:05:52

0

创建当前线程处理你在哪里注册您的监听器并将其作为第三个参数传递给监听器。

public void run() { 
    Log.d("RunTag", Thread.currentThread().getName()); // To display thread 
    mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE ); 
    mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
    MySensorListener msl = new MySensorListener(); 
    Looper.perpare; 
    Handler hndlr = new Handler(); 

    mSensorManager.registerListener(msl, mSensor, 
    SensorManager.SENSOR_DELAY_UI, hndlr); 
    Looper.loop; 

    } 
1

获取线程处理程序并在该线程中注册侦听器。例如:

public void run() { 
    Sensor sensor = this.sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); 
    Looper.prepare(); 
    Handler gHandler = new Handler(); 
    this.sensorManager.registerListener(gravitySensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, gHandler); 
    Looper.loop(); 
} 

希望这可以帮到你。