关键部分在onSensorChanged()中不起作用

时间:2012-08-12 18:51:58

标签: java android multithreading android-sensors

我是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实例)都不适合我。

2 个答案:

答案 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);
}