You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android牛铃APP摇一摇播放音效失效问题求助

问题分析与解决方案

你的摇一摇功能无法触发的核心原因有几个:

  1. 未注册传感器监听器:创建了ShakeDetector但未绑定到SensorManager,导致传感器事件无法传递给摇一摇检测器。
  2. OnShakeListener引用错误:OnShakeListener是ShakeDetector的内部接口,未明确指定所属类会引发编译错误。
  3. 忽略负向加速度:当前代码仅比较线性加速度原始值,未取绝对值,导致负方向摇晃(如向左、向下)无法被检测。
  4. MediaPlayer状态管理缺失:局部变量的MediaPlayer在播放结束后未重置,重复调用start()无效。
  5. 未绑定Activity生命周期:未在onResume/onPause中注册/注销监听器,既浪费电量也可能导致内存泄漏。

修正后的代码

MainActivity.java

import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import androidx.appcompat.app.AppCompatActivity;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {
    private ImageButton imageButton;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private ShakeDetector mShakeDetector;
    // 将MediaPlayer改为类成员变量,方便生命周期管理
    private MediaPlayer mediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageButton = findViewById(R.id.imageButton);
        mediaPlayer = MediaPlayer.create(this, R.raw.cowbell);

        imageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                playCowbellSound();
            }
        });

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        // 正确引用内部接口
        mShakeDetector = new ShakeDetector(new ShakeDetector.OnShakeListener(){
            @Override
            public void onShake(){
                playCowbellSound();
            }
        });
    }

    // 封装播放逻辑,处理MediaPlayer状态
    private void playCowbellSound() {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
        }
        mediaPlayer.reset();
        try {
            mediaPlayer.setDataSource(this, Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.cowbell));
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 注册传感器监听器,选择合适的采样率
        if (mAccelerometer != null) {
            mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 注销监听器,节省电量
        mSensorManager.unregisterListener(mShakeDetector);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放MediaPlayer资源
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

ShakeDetector.java

修正加速度绝对值判断,并可调整灵敏度:

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

public class ShakeDetector implements SensorEventListener {

    // 灵敏度调整:数值越大,需要摇晃越剧烈才能触发
    private static final int MIN_SHAKE_ACCELERATION = 10;

    private static final int MIN_MOVEMENTS = 2;
    private static final int MAX_SHAKE_DURATION = 500;

    private final float[] mGravity = { 0.0f, 0.0f, 0.0f };
    private final float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };

    private static final int X = 0;
    private static final int Y = 1;
    private static final int Z = 2;

    private final OnShakeListener mShakeListener;
    long startTime = 0;
    int moveCount = 0;

    public ShakeDetector(OnShakeListener shakeListener) {
        mShakeListener = shakeListener;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        setCurrentAcceleration(event);
        float maxLinearAcceleration = getMaxCurrentLinearAcceleration();

        if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
            long now = System.currentTimeMillis();

            if (startTime == 0) {
                startTime = now;
            }

            long elapsedTime = now - startTime;

            if (elapsedTime > MAX_SHAKE_DURATION) {
                resetShakeDetection();
            } else {
                moveCount++;

                if (moveCount > MIN_MOVEMENTS) {
                    mShakeListener.onShake();
                    resetShakeDetection();
                }
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

    private void setCurrentAcceleration(SensorEvent event) {
        final float alpha = 0.8f;

        mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
        mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
        mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];

        mLinearAcceleration[X] = event.values[X] - mGravity[X];
        mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
        mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];
    }

    // 修正:取加速度绝对值,确保所有方向摇晃都能被检测
    private float getMaxCurrentLinearAcceleration() {
        float xAbs = Math.abs(mLinearAcceleration[X]);
        float yAbs = Math.abs(mLinearAcceleration[Y]);
        float zAbs = Math.abs(mLinearAcceleration[Z]);

        return Math.max(xAbs, Math.max(yAbs, zAbs));
    }

    private void resetShakeDetection() {
        startTime = 0;
        moveCount = 0;
    }

    public interface OnShakeListener {
        void onShake();
    }
}

关键修复点说明

  • 传感器注册:在onResume中注册监听器,onPause中注销,确保仅在Activity可见时监听,同时选择SENSOR_DELAY_GAME采样率平衡响应速度与性能。
  • 接口引用:使用ShakeDetector.OnShakeListener明确指定接口所属类,解决编译错误。
  • 加速度绝对值判断:修正getMaxCurrentLinearAcceleration方法,取各轴加速度绝对值,覆盖所有方向的摇晃动作。
  • MediaPlayer管理:封装播放逻辑,每次播放前重置并重新准备,确保重复播放有效;在onDestroy中释放资源,避免内存泄漏。
  • 灵敏度调整:通过修改MIN_SHAKE_ACCELERATION数值调整摇一摇灵敏度,数值越大需要摇晃越剧烈。

内容的提问来源于stack exchange,提问作者e36_King

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 05:47:01