Android牛铃APP摇一摇播放音效失效问题求助
问题分析与解决方案
你的摇一摇功能无法触发的核心原因有几个:
- 未注册传感器监听器:创建了
ShakeDetector但未绑定到SensorManager,导致传感器事件无法传递给摇一摇检测器。 OnShakeListener引用错误:OnShakeListener是ShakeDetector的内部接口,未明确指定所属类会引发编译错误。- 忽略负向加速度:当前代码仅比较线性加速度原始值,未取绝对值,导致负方向摇晃(如向左、向下)无法被检测。
- MediaPlayer状态管理缺失:局部变量的
MediaPlayer在播放结束后未重置,重复调用start()无效。 - 未绑定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
相关产品推荐
相关产品推荐

