2010-07-20 40 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(); 
} 

希望這可以幫到你。