1

我是 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.

此外,此变量被声明为volatile,因此任何输入关键变量的人都应该有一个新的、最新的值。但似乎两个不同的线程实际上同时进入了临界区,它们都具有相同的标志值。这怎么可能发生,我错在哪里?

PS这里的那个人似乎也有同样的问题,但没有一个解决方案MediaPlayer适合我。

4

2 回答 2

0

假设您进入“isAccelChanged() if”内部,则无论stopped 的值如何,您总是在“onSensorChanged”内启动播放器中的声音(它在if 之外,并且在同步块之外)。

如果您确定只有一个实例,则可以摆脱“同步”。

检查并回复。

于 2012-08-12T19:13:05.300 回答
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);
}
于 2012-08-13T16:04:22.983 回答