SensorEventListener位于单独的线程中

时间:2010-07-20 03:33:42

标签: android events

这似乎是一个基本问题,但经过一段时间的搜索和玩耍之后,我已经到了可以欣赏一些帮助的地步。我想让一个SensorEventListener在一个与UI不同的线程中运行,这样当事件进入时需要进行的计算不会减慢UI的速度。

我的最新尝试如下:

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()的activity(或service)中,我创建一个SensorThread对象并调用其start()方法。正如您所料,调试日志显示新线程中的“RunTag”条目。但onSensorChanged()的“ListenerTag”正在主线程中运行,即使它的对象在新线程中被实例化。我该如何改变?

5 个答案:

答案 0 :(得分:14)

有点晚了,但如果其他人还想知道,这是实现这一目标的好方法。和多线程一样,确保你知道自己在做什么并花时间去做,以避免那些奇怪的错误。玩得开心!

班级成员:

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

答案 1 :(得分:13)

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

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

答案 2 :(得分:6)

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

答案 3 :(得分: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();
}
希望这会对你有所帮助。

答案 4 :(得分: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;

    }