我是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=trueonSensorChanged()和onCompletion()中的关键部分被锁定在同一个对象上(我在程序中只创建了一个AccelListener实例),因此不应该有对stopped的并行访问。
此外,这个变量被声明为volatile,所以任何输入临界值的人都应该有一个新的、最新的值。但是,看起来两个不同的线程实际上同时进入了关键部分,它们都具有相同的标志值。这怎么会发生,我哪里错了?
这里上的那个家伙似乎也有同样的问题,但是对于他的情况,没有一个解决方案(比如在不同的对象上同步或者使用相同的MediaPlayer实例)对我起作用。
发布于 2012-08-13 16:04:22
问题解决了。我没有注销AccelListener,而且调试器似乎没有正确地停止运行程序的版本。每个连续的Run命令都只是启动了main活动,它实例化了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);
}发布于 2012-08-12 19:13:05
假设您在"isAccelChanged() if“中输入,则始终在"onSensorChanged”内启动播放机中的声音,而不考虑stopped的值(它不在if中,也不在同步块之外)。
如果你确信你只有一个实例,你可以去掉“同步”。
检查一下,然后回复。
https://stackoverflow.com/questions/11924873
复制相似问题