Android(安卓)摇一摇太灵敏的解决方法
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.
更多相关文章
- 关于visibility的属性值visible,invisible,gone的区别
- Android(安卓)studio 删除无用代码
- 利用Handler来更新android的UI(1)
- android 如何调用选择文件模块
- Android(安卓)Studio 快捷键
- android 界面跳转
- parsing XML: unbound prefix
- android 自定义Dialog背景透明及显示位置设置
- Android(安卓)Studio之Instant Run