现在的位置: 首页 > 综合 > 正文

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

2013年10月26日 ⁄ 综合 ⁄ 共 3721字 ⁄ 字号 评论关闭

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

想到这个功能可能应用广泛,比如摇晃手机换图片、截图、洗牌、结束当前程序等,所以找了些资料,并加以改进,将此功能封装成类(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.   
  3. import java.util.ArrayList; 
  4. import android.content.Context; 
  5. import android.hardware.Sensor; 
  6. import android.hardware.SensorEvent; 
  7. import android.hardware.SensorEventListener; 
  8. import android.hardware.SensorManager; 
  9. import android.util.FloatMath; 
  10.   
  11. /** 
  12. * 用于检测手机晃动 
  13. *  
  14. * @author 郑智仁 
  15. */
  16. public class ShakeDetector implements SensorEventListener { 
  17.     /** 
  18.      * 检测的时间间隔 
  19.      */
  20.     static final int UPDATE_INTERVAL = 100; 
  21.     /** 
  22.      * 上一次检测的时间 
  23.      */
  24.     long mLastUpdateTime; 
  25.     /** 
  26.      * 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。 
  27.      */
  28.     float mLastX, mLastY, mLastZ; 
  29.     Context mContext; 
  30.     SensorManager mSensorManager; 
  31.     ArrayList<OnShakeListener> mListeners; 
  32.     /** 
  33.      * 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。 
  34.      */
  35.     public int shakeThreshold = 5000; 
  36.   
  37.     public ShakeDetector(Context context) { 
  38.         mContext = context; 
  39.         mSensorManager = (SensorManager) context 
  40.                 .getSystemService(Context.SENSOR_SERVICE); 
  41.         mListeners = new ArrayList<OnShakeListener>(); 
  42.     } 
  43.   
  44.     /** 
  45.      * 当摇晃事件发生时,接收通知 
  46.      */
  47.     public interface OnShakeListener { 
  48.         /** 
  49.          * 当手机晃动时被调用 
  50.          */
  51.         void onShake(); 
  52.     } 
  53.   
  54.     /** 
  55.      * 注册OnShakeListener,当摇晃时接收通知 
  56.      *  
  57.      * @param listener 
  58.      */
  59.     public void registerOnShakeListener(OnShakeListener listener) { 
  60.         if (mListeners.contains(listener)) 
  61.             return; 
  62.         mListeners.add(listener); 
  63.     } 
  64.   
  65.     /** 
  66.      * 移除已经注册的OnShakeListener 
  67.      *  
  68.      * @param listener 
  69.      */
  70.     public void unregisterOnShakeListener(OnShakeListener listener) { 
  71.         mListeners.remove(listener); 
  72.     } 
  73.   
  74.     /** 
  75.      * 启动摇晃检测 
  76.      */
  77.     public void start() { 
  78.         if (mSensorManager == null) { 
  79.             throw new UnsupportedOperationException(); 
  80.         } 
  81.         Sensor sensor = mSensorManager 
  82.                 .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
  83.         if (sensor == null) { 
  84.             throw new UnsupportedOperationException(); 
  85.         } 
  86.         boolean success = mSensorManager.registerListener(this, sensor, 
  87.                 SensorManager.SENSOR_DELAY_GAME); 
  88.         if (!success) { 
  89.             throw new UnsupportedOperationException(); 
  90.         } 
  91.     } 
  92.   
  93.     /** 
  94.      * 停止摇晃检测 
  95.      */
  96.     public void stop() { 
  97.         if (mSensorManager != null) 
  98.             mSensorManager.unregisterListener(this); 
  99.     } 
  100.   
  101.     @Override
  102.     public void onAccuracyChanged(Sensor sensor, int accuracy) { 
  103.         // TODO Auto-generated method stub 
  104.     } 
  105.   
  106.     @Override
  107.     public void onSensorChanged(SensorEvent event) { 
  108.         long currentTime = System.currentTimeMillis(); 
  109.         long diffTime = currentTime - mLastUpdateTime; 
  110.         if (diffTime < UPDATE_INTERVAL) 
  111.             return; 
  112.         mLastUpdateTime = currentTime; 
  113.         float x = event.values[0]; 
  114.         float y = event.values[1]; 
  115.         float z = event.values[2]; 
  116.         float deltaX = x - mLastX; 
  117.         float deltaY = y - mLastY; 
  118.         float deltaZ = z - mLastZ; 
  119.         mLastX = x; 
  120.         mLastY = y; 
  121.         mLastZ = z; 
  122.         float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ 
  123.                 * deltaZ) 
  124.                 / diffTime * 10000; 
  125.         if (delta > shakeThreshold) { // 当加速度的差值大于指定的阈值,认为这是一个摇晃 
  126.             this.notifyListeners(); 
  127.         } 
  128.     } 
  129.   
  130.     /** 
  131.      * 当摇晃事件发生时,通知所有的listener 
  132.      */
  133.     private void notifyListeners() { 
  134.         for (OnShakeListener listener : mListeners) { 
  135.             listener.onShake(); 
  136.         } 
  137.     } 
  138. }

复制代码

如何使用ShakeDetector

1、new一个ShakeDetector

2、调用mShakeDetector.registerOnShakeListener()注册一个OnShakeListener

3、在OnShakeListener的onShake函数中,处理摇晃事件

4、调用mShakeDetector.start()启动摇晃检测

抱歉!评论已关闭.