1 简介

最近开发android 摇一摇显示日志功能,结果发现,太敏感了,随便动一下手机就会震动,研究了一下这个问题,遂写这篇博客记录下来。

2 基本代码

(1) Android摇一摇就是利用加速度传感器来感知手机的方位,基本代码如下:
MainActivity.java

public class MainActivity extends AppCompatActivity {    private SensorManager sensorManager;    private Vibrator vibrator;    private ShakeListener shakeListener;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);        vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);        shakeListener = new ShakeListener();        sensorManager.registerListener(shakeListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), sensorManager.SENSOR_DELAY_NORMAL);    }    //摇一摇监听器    public class ShakeListener implements SensorEventListener {        @Override        public void onSensorChanged(SensorEvent event) {            //values[0]:X轴,values[1]:Y轴,values[2]:Z轴            float[] values = event.values;            if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15 || Math.abs(values[2]) > 15)) {                //摇动手机后,再伴随震动提示~~                vibrator.vibrate(500);            }        }        @Override        public void onAccuracyChanged(Sensor sensor, int accuracy) {        }    }}

界面代码忽略不计,增加下面的权限:

 <uses-permission android:name="android.permission.VIBRATE"/>    <uses-permission android:name="android.hardware.sensor.accelerometer"/>

(2) 代码解释

sensorManager.registerListener(shakeListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), sensorManager.SENSOR_DELAY_NORMAL);

第一个参数是监听器
第二个参数是传感器类型,Sensor.TYPE_ACCELEROMETER 表示加速度传感器
第三个参数是回调的频率,sensorManager.SENSOR_DELAY_NORMAL 表示正常速度

(3) 方向解释

public void onSensorChanged(SensorEvent event) {            //values[0]:X轴,values[1]:Y轴,values[2]:Z轴            float[] values = event.values;            if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15 || Math.abs(values[2]) > 15)) {                //摇动手机后,再伴随震动提示~~                vibrator.vibrate(500);            }        }

float[] values = event.values;有三个值,分别表示x,y,z上的偏移量
用网上的图来解释一下x,y,z的含义:

把手机平放在桌面上,然后从右边向左边翻过来,盖在桌面上,这个过程z的值从正数到负数

把手机平方在桌面上,然后把头抬起来,Y值是正数,不断变大;然后把尾部台起来,Y值是负数,绝对值不断变大

把手机竖直拿在手中,屏幕正对自己,然后向左倾斜,注意是倾斜不是平移,x的值是正数,不断变大;向右倾斜,x是负数,绝对值不断变大

3 问题

这样写的代码是有问题的,太灵敏了,只要一动就会震动,打出日志一看,onSensorChanged()是在不停的回调的,如果竖直拿着手机,向左倾斜,然后保持不动,你会发现 x 的值基本不变,而且是个很大的值,这样就不停的在震动,显然这不是摇一摇。

怎么办呢?
后来参考了ios,问了ios的摇一摇是怎么实现的,原来ios把一次摇动的变化过程作为一个事件,由系统发给你,也就是说你只有动了,有个变化过程,它才给你事件,而且只给一个,不像Android,尼玛,不停的告诉你。

解决的思路找到了,我们判断的条件不应该是最大值,而应该是变化的快慢,也就是速度,换句话说,我们要计算摇动的速度,通过x,y,z计算空间移动的距离,除以移动时间,就得到了速度,好吧,太复杂了,直接上代码

4 解决方法

判断摇动的速度,而不是摇动后的左标是否达到某一个值
正确的代码如下:

public class MainActivity extends AppCompatActivity {    private SensorManager sensorManager;    private Vibrator vibrator;    private ShakeListener shakeListener;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);        vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);        shakeListener = new ShakeListener();        sensorManager.registerListener(shakeListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), sensorManager.SENSOR_DELAY_NORMAL);    }    //摇一摇监听器    public class ShakeListener implements SensorEventListener {        /** * 检测的时间间隔 */        static final int UPDATE_INTERVAL = 100;        /** * 上一次检测的时间 */        long mLastUpdateTime;        /** * 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。 */        float mLastX, mLastY, mLastZ;        /** * 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。 */        public int shakeThreshold = 4000;        @Override        public void onSensorChanged(SensorEvent event) {            long currentTime = System.currentTimeMillis();            long diffTime = currentTime - mLastUpdateTime;            if (diffTime < UPDATE_INTERVAL) {                return;            }            mLastUpdateTime = currentTime;            float x = event.values[0];            float y = event.values[1];            float z = event.values[2];            float deltaX = x - mLastX;            float deltaY = y - mLastY;            float deltaZ = z - mLastZ;            mLastX = x;            mLastY = y;            mLastZ = z;            float delta = (float) (Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / diffTime * 10000);            // 当加速度的差值大于指定的阈值,认为这是一个摇晃            if (delta > shakeThreshold) {                vibrator.vibrate(200);            }        }        @Override        public void onAccuracyChanged(Sensor sensor, int accuracy) {        }    }}

经过测试,这段代码很好的实现了摇一摇功能。

5 转载请注明来自”梧桐那时雨”的博客“:http://blog.csdn.net/fuchaosz/article/details/51744078

Tips
如果觉得这篇博客对你有帮助或者喜欢博主的写作风格,就给博主留个言或者顶一下呗,鼓励博主创作出更多优质博客,Thank you.

更多相关文章

  1. android 修改键盘enter图标,设置搜索等图标
  2. javafx控件的显示与隐藏
  3. 如何编写高效的android代码(1)
  4. Android中改变Activity的不同icon:activity-alias
  5. Android源代码下载
  6. android Shape使用
  7. Android设置透明、半透明等效果
  8. Android实现九宫格 主界面应用列表效果
  9. android横竖屏切换

随机推荐

  1. android kernel和标准linux kernel的区别
  2. webViewJavascriptBridge踩坑【页面刚开
  3. Android打开WLAN开关的广播状态监听
  4. android 开发包简介
  5. 使用Android中的Parcelable序列化对象
  6. 在Android中通过Java修改文件权限
  7. android 输入框EditText禁止输入Emoji表
  8. Android(安卓)-- ListView(1)
  9. Android面经总结
  10. android 创建数字签名应用程序