2012-08-12 21 views
1

我是Android開發新手。我正在構建一個簡單的Android應用程序,用於分析accelerometer sensor數據,並用MediaPlayer播放聲音。對於SensorEventListener實現代碼:關鍵部分無法在onSensorChanged()

class AccelListener implements SensorEventListener { 
     boolean firstUpdate = true; 
     volatile boolean stopped = true; 
     private MediaPlayer mplayer; 
      //some variables to store calculations 

     public AccelListener(MediaPlayer mediaplayer) { 
      mplayer = mediaplayer; 
      mplayer.setOnCompletionListener(new OnCompletionListener() { 
       public void onCompletion(MediaPlayer mp) { 
        if (mplayer == mp) { 
         synchronized (AccelListener.this) { 
          stopped = true; 
         } 
         Log.d("MediaPlayer Callback", "stopped=" + stopped); 
        } 
       } 
      }); 
     } 

    public void onSensorChanged(SensorEvent event) { 
     updateAccel(event.values); 
     if (isAccelChanged()) { 
      Log.d("Accel Listener", "stopped_before=" + stopped); 
      synchronized (this) { 
       if (stopped) { 
        stopped = false; 
        firstUpdate = true; 
        mplayer.start(); 
        Log.d("Accel Listener", "stopped_after=" + stopped); 
       } 
      } 
     } 
    }  
} 

的問題是,當我啓動應用程序,並開始搖晃手機,聲音在同一時刻扮演了好幾次。音頻文件長約3-4秒,所以它沒有辦法播放到最後,然後對下一次搖動做出反應。

logcat的示出了以下內容:在onSensorChanged()onCompletion()

08-12 22:16:24.693: D/Accel Listener(5382): stopped_before=true 
08-12 22:16:24.693: D/Accel Listener(5382): stopped_after=false 
08-12 22:16:24.693: D/Accel Listener(5382): stopped_before=true 
08-12 22:16:24.703: D/Accel Listener(5382): stopped_after=false 
08-12 22:16:28.777: D/MediaPlayer Callback(5382): stopped=true 
08-12 22:16:28.777: D/MediaPlayer Callback(5382): stopped=true 

關鍵段被鎖定相同的對象(I使只有一個節目的AccelListener實例)上,所以應該沒有並行訪問stopped

此外,這個變量被聲明爲volatile,所以任何進入關鍵的人都應該有一個新的最新值。但似乎兩個不同線程實際上同時進入臨界區域,兩者都具有相同的標誌值。這怎麼可能發生,我錯在哪裏?

P.S. here的傢伙似乎也有同樣的問題,但他的案例(例如在單獨的對象上同步或使用同一個MediaPlayer實例)的解決方案都不適用於我。

回答

0

問題已解決。我沒有取消註冊AccelListener,似乎調試器沒有正確停止正在運行的程序版本。每個連續的Run命令剛開始主要活動,它實例化AccelListener,註冊它,等等。添加以下代碼,固定了整個事情:

@Override 
protected void onPause() { 
    super.onPause(); 
    sensMgr.unregisterListener(grListener); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    sensMgr.registerListener(grListener, 
      sensMgr.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION), 
      SensorManager.SENSOR_DELAY_GAME); 
} 
0

假設你進入「isAccelChanged()if」的內部,你總是在「onSensorChanged」中的播放器中啓動聲音,而不管停止的值(它超出了if和out塊)。

如果你確定你只有一個實例,你可以擺脫「同步」。

檢查出來並回復。

+0

我推測,如果**(!停止){回報;} ** **時停止=假**只會中止執行梅託德,使** mplayer.start()**無法訪問。刪除同步並沒有改變任何東西,也沒有將** mplayer.start()**移動到臨界區。 – 2012-08-12 19:43:02

+0

Ahh ..是正確的!應該無法訪問。並且再次如此,這意味着從「如果」到「Log.d」有人正在改變停止的值。很奇怪。 你能分享你使用的最終代碼嗎? – 2012-08-12 19:52:41

+0

更新的代碼。儘管我留下了'同步'塊,因爲沒有它們的版本是我開始使用的那個版本,它並沒有幫助。 – 2012-08-12 20:16:06