我是Android开发的新手。我正在构建一个简单的Android应用程序,用于分析accelerometer sensor
数据并使用MediaPlayer
播放声音。 SensorEventListener
实施代码:
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显示以下内容:
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
onSensorChanged()
和onCompletion()
中的关键部分被锁定在同一个对象上(我在程序中只创建了AccelListener
的一个实例),因此不应该对stopped
进行并行访问{1}}。
此外,此变量声明为volatile
,因此输入关键字的任何人都应该拥有新的最新值。但似乎两个不同的线程实际上同时进入临界区,两者都具有相同的标志值。怎么会发生这种情况,我错在哪里?
P.S。 here以上的人似乎也遇到了同样的问题,但是他的案例解决方案(例如在单独的对象上同步或使用相同的MediaPlayer
实例)都不适合我。
答案 0 :(得分:0)
假设你进入“isAccelChanged()if”的内部,你总是在“onSensorChanged”内的播放器中启动声音,而不管停止的值是什么(它超出了if,并且超出了synchronized块)。
如果您确定只有一个实例,则可以摆脱“同步”。
检查出来并回复。
答案 1 :(得分: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);
}