[Android实例] Android ShakeDetector(摇晃检测)教程详解

最近要实现一个手机摇晃 的功能。

想到这个功能可能应用广泛,比如摇晃手机换图片、截图、洗牌、结束当前程序等,所以找了些资料,并加以改进,将此功能封装成类(ShakeDetector),方便今后使用。
摇晃检测基于加速传感器(Sensor.TYPE_ACCELEROMETER)。

由于重力的存在,当手机静止放于桌面时,加速传感器也是有加速度的。所以,仅通过是否有加速度来判断摇晃是不行的。
那么,判断加速度的变化吧。在一个较短的时间间隔求出加速度的差值,跟一个指定的阈值比较,如果差值大于阈值,则认为是摇晃发生了。ClingMarks的方法将x、y、z方向的加速度差值简单的加起来,我认为不是很准确。

加速度是向量,求差应该是各方向的差值平方后相加,再开方。(数学忘光了,应该没记错吧。)
所以就有了这行代码:

  1. float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / diffTime * 10000;
复制代码
功能封装成类 ShakeDetector,实现了SensorEventListener接口,用于向系统注册传感器事件的Listener。

  1. package zhengzhiren.android.hardware;

  2. import java.util.ArrayList;
  3. import android.content.Context;
  4. import android.hardware.Sensor;
  5. import android.hardware.SensorEvent;
  6. import android.hardware.SensorEventListener;
  7. import android.hardware.SensorManager;
  8. import android.util.FloatMath;

  9. /**
  10. * 用于检测手机晃动
  11. *
  12. * @author 郑智仁
  13. */
  14. public class ShakeDetector implements SensorEventListener {
  15. /**
  16. * 检测的时间间隔
  17. */
  18. static final int UPDATE_INTERVAL = 100;
  19. /**
  20. * 上一次检测的时间
  21. */
  22. long mLastUpdateTime;
  23. /**
  24. * 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。
  25. */
  26. float mLastX, mLastY, mLastZ;
  27. Context mContext;
  28. SensorManager mSensorManager;
  29. ArrayList<OnShakeListener> mListeners;
  30. /**
  31. * 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。
  32. */
  33. public int shakeThreshold = 5000;

  34. public ShakeDetector(Context context) {
  35. mContext = context;
  36. mSensorManager = (SensorManager) context
  37. .getSystemService(Context.SENSOR_SERVICE);
  38. mListeners = new ArrayList<OnShakeListener>();
  39. }

  40. /**
  41. * 当摇晃事件发生时,接收通知
  42. */
  43. public interface OnShakeListener {
  44. /**
  45. * 当手机晃动时被调用
  46. */
  47. void onShake();
  48. }

  49. /**
  50. * 注册OnShakeListener,当摇晃时接收通知
  51. *
  52. * @param listener
  53. */
  54. public void registerOnShakeListener(OnShakeListener listener) {
  55. if (mListeners.contains(listener))
  56. return;
  57. mListeners.add(listener);
  58. }

  59. /**
  60. * 移除已经注册的OnShakeListener
  61. *
  62. * @param listener
  63. */
  64. public void unregisterOnShakeListener(OnShakeListener listener) {
  65. mListeners.remove(listener);
  66. }

  67. /**
  68. * 启动摇晃检测
  69. */
  70. public void start() {
  71. if (mSensorManager == null) {
  72. throw new UnsupportedOperationException();
  73. }
  74. Sensor sensor = mSensorManager
  75. .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  76. if (sensor == null) {
  77. throw new UnsupportedOperationException();
  78. }
  79. boolean success = mSensorManager.registerListener(this, sensor,
  80. SensorManager.SENSOR_DELAY_GAME);
  81. if (!success) {
  82. throw new UnsupportedOperationException();
  83. }
  84. }

  85. /**
  86. * 停止摇晃检测
  87. */
  88. public void stop() {
  89. if (mSensorManager != null)
  90. mSensorManager.unregisterListener(this);
  91. }

  92. @Override
  93. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  94. // TODO Auto-generated method stub
  95. }

  96. @Override
  97. public void onSensorChanged(SensorEvent event) {
  98. long currentTime = System.currentTimeMillis();
  99. long diffTime = currentTime - mLastUpdateTime;
  100. if (diffTime < UPDATE_INTERVAL)
  101. return;
  102. mLastUpdateTime = currentTime;
  103. float x = event.values[0];
  104. float y = event.values[1];
  105. float z = event.values[2];
  106. float deltaX = x - mLastX;
  107. float deltaY = y - mLastY;
  108. float deltaZ = z - mLastZ;
  109. mLastX = x;
  110. mLastY = y;
  111. mLastZ = z;
  112. float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
  113. * deltaZ)
  114. / diffTime * 10000;
  115. if (delta > shakeThreshold) { // 当加速度的差值大于指定的阈值,认为这是一个摇晃
  116. this.notifyListeners();
  117. }
  118. }

  119. /**
  120. * 当摇晃事件发生时,通知所有的listener
  121. */
  122. private void notifyListeners() {
  123. for (OnShakeListener listener : mListeners) {
  124. listener.onShake();
  125. }
  126. }
  127. }
复制代码
如何使用ShakeDetector

1、new一个ShakeDetector
2、调用mShakeDetector.registerOnShakeListener()注册一个OnShakeListener
3、在OnShakeListener的onShake函数中,处理摇晃事件
4、调用mShakeDetector.start()启动摇晃检测

你可能感兴趣的:(android)