1

Android開発初心者です。データを分析accelerometer sensorしてサウンドを再生する単純な Android アプリケーションを作成してい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

とのクリティカル セクションは同じオブジェクトでロックされているため (プログラムで のインスタンスを 1 つだけ作成しますonSensorChanged()) 、 への並列アクセスはありません。onCompletion()AccelListenerstopped

さらに、この変数は として宣言されてvolatileいるため、クリティカルを入力する人は誰でも新鮮で最新の値を持つ必要があります。しかし、実際には 2 つの異なるスレッドが同時にクリティカル セクションに入るようで、両方とも同じフラグ値を持っています。これはどのように発生する可能性があり、どこが間違っていますか?

PSここにいる男も同じ問題を抱えているようですが、彼の場合の解決策(別のオブジェクトでの同期や の同じインスタンスの使用などMediaPlayer)はどれもうまくいきませんでした。

4

2 に答える 2

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 に答える
0

「isAccelChanged() if」内に入ると仮定すると、stopped の値に関係なく、常に「onSensorChanged」内でプレーヤーでサウンドが開始されます (if 外であり、同期ブロック外です)。

インスタンスが 1 つしかないことが確実な場合は、「同期された」インスタンスを取り除くことができます。

確認してから返信してください。

于 2012-08-12T19:13:05.300 に答える