最近做一个摇一摇的功能 网上相关代码很多 但是这次的需求有点奇葩 要求是摇两次才生效
看起来好像很简单 但真正要做遇到的问题还是很多 时间限制 机型灵敏性 摇动的方式 弄了一周多 做出的效果算一般吧
原理介绍
其实就是加速度传感器的使用 开发传感器应用的步骤如下
1 调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取 SensorManager对象
SensorManager代表系统的传感器管理服务2 调用SensorManager的getDefaultSensor(int type)获取指定类型的传感器
3 在Activity的onResume()方法中调用SensorManager的registerListener()为指定传感器注册监听
程序通过实现监听器可获取传感器传回来的数据
registerListener(SensorEventListener listener, Sensor sensor, int rateUs)
listener 监听传感器事件的监听器 该监听需要实现SensorEventListener接口
sensor 传感器对象
rateUs 获取传感器数据的频率 支持4个频率值
SENSOR_DELAY_FASTEST 最快 延迟小 耗电
SENSOR_DELAY_GAME 适合游戏
SENSOR_DELAY_UI 正常频率
SENSOR_DELAY_NORMAL 省电 延迟大
上代码
public class AccelerometerTest extends Activity implements SensorEventListener { // 定义系统的Sensor管理器 SensorManager sensorManager; EditText etTxt1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取程序界面上的文本框组件 etTxt1 = (EditText) findViewById(R.id.txt1); // 获取系统的传感器管理服务 sensorManager = (SensorManager) getSystemService( Context.SENSOR_SERVICE); //① } @Override protected void onResume() { super.onResume(); // 为系统的加速度传感器注册监听器 sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME); //② } @Override protected void onStop() { // 取消注册 sensorManager.unregisterListener(this); super.onStop(); } // 以下是实现SensorEventListener接口必须实现的方法 // 当传感器的值发生改变时回调该方法 @Override public void onSensorChanged(SensorEvent event) { float[] values = event.values; StringBuilder sb = new StringBuilder(); sb.append("X方向上的加速度:"); sb.append(values[0]); sb.append("\nY方向上的加速度:"); sb.append(values[1]); sb.append("\nZ方向上的加速度:"); sb.append(values[2]); etTxt1.setText(sb.toString()); } // 当传感器精度改变时回调该方法。 @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/tip" /> <EditText android:id="@+id/txt1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:editable="false" android:cursorVisible="false" /> </LinearLayout>
返回的三个值分别代表在X Y Z三个方向上的加速度
X轴沿屏幕向左
Y轴沿屏幕向上
Z轴垂直于屏幕向里
下面给出双甩功能的代码 主要原理是判断速度阀值 并加入时间限制
MainActivity
public class MainActivity extends Activity{ EditText etTxt1; private ShakeListener mShakeListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etTxt1 = (EditText) findViewById(R.id.txt1); } @Override protected void onResume() { super.onResume(); //注册 mShakeListener = new ShakeListener(this); mShakeListener.setOnShakeListener(new ShakeListener.OnShakeListener() { @Override public void onShake() { Log.i("TAG", "震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动"); Vibrator vVi = (Vibrator)getSystemService(Service.VIBRATOR_SERVICE); vVi.vibrate(400); StringBuilder sb = new StringBuilder(); sb.append(mShakeListener.getSpeed()); etTxt1.setText(sb.toString()); } }); } @Override protected void onStop() { super.onStop(); // 取消注册 mShakeListener.stop(); } }
ShakeListener
public class ShakeListener implements SensorEventListener { private Context mContext; private Sensor sensor; // 传感器 private SensorManager sensorManager; // 传感器管理器 private OnShakeListener onShakeListener; // 手机上一个位置时重力感应坐标 private float lastX; private float lastY; private float lastZ; private double speed; private long lastUpdateTime; int UPTATE_INTERVAL_TIME = 70;// 两次检测的时间间隔 int SPEED_SHRESHOLD = 3000;// 速度阈值 // 双甩 int count = 0; int timeSlice = 0; // 时间片 final int GET_SUCC = 0; Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case GET_SUCC: count = 0; timeSlice = 0; break; } } }; public ShakeListener(Context mContext) { super(); this.mContext = mContext; start(); } //开始 public void start() { // 获得传感器管理器 sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); if (sensorManager != null) { // 获得重力传感器 sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } // 注册 if (sensor != null) { sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST); } } //停止 public void stop() { sensorManager.unregisterListener(this); } // 设置重力感应监听器 public void setOnShakeListener(OnShakeListener listener) { onShakeListener = listener; } @Override public void onSensorChanged(SensorEvent event) { long currentUpdateTime = System.currentTimeMillis(); // 现在检测时间 long timeInterval = currentUpdateTime - lastUpdateTime; // 两次检测的时间间隔 if (timeInterval < UPTATE_INTERVAL_TIME) // 判断是否达到了检测时间间隔 return; lastUpdateTime = currentUpdateTime; // 现在的时间变成last时间 float[] values = event.values; // 获得x,y,z坐标 float x = event.values[0]; float y = event.values[1]; float z = event.values[2]; // 获得x,y,z的变化值 float deltaX = x - lastX; float deltaY = y - lastY; float deltaZ = z - lastZ; // 将现在的坐标变成last坐标 lastX = x; lastY = y; lastZ = z; speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * 10000 / timeInterval; Log.i("TAG", "speed" + speed); Log.i("TAG", "count---" + count); Log.i("TAG", "timeSlice---" + timeSlice); //限制两次摇动在1S的时间内 if (count == 1) { timeSlice++; if (timeSlice * UPTATE_INTERVAL_TIME > 1000) { count = 0; timeSlice = 0; } } if (speed > SPEED_SHRESHOLD) { Log.i("TAG", " 摇一摇---------------------------------------------------------------------------------------------------摇一摇"); count++; if (count == 2) { count = 0; //如果两次触发在300毫秒之内 只能算一次 if (timeSlice * UPTATE_INTERVAL_TIME < 300) { count = 1; } else { onShakeListener.onShake(); handler.removeMessages(GET_SUCC); handler.sendEmptyMessageDelayed(GET_SUCC, 300); } timeSlice = 0; } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } public interface OnShakeListener { public void onShake(); } public double getSpeed() { return speed; } }
activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.accelerometertest.MainActivity" > <EditText android:id="@+id/txt1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
加速度传感器Demo https://github.com/huanyi0723/Accelerometer/
双甩功能Demo https://github.com/huanyi0723/AccelerometerTest/