在Android2.3 gingerbread系统中,google提供了11种传感器供应用层使用,具体如下:(Sensor类)
#define SENSOR_TYPE_ACCELEROMETER 1 //加速度
#define SENSOR_TYPE_MAGNETIC_FIELD 2 //磁力
#define SENSOR_TYPE_ORIENTATION 3 //方向
#define SENSOR_TYPE_GYROSCOPE 4 //陀螺仪
#define SENSOR_TYPE_LIGHT 5 //光线感应
#define SENSOR_TYPE_PRESSURE 6 //压力
#define SENSOR_TYPE_TEMPERATURE 7 //温度
#define SENSOR_TYPE_PROXIMITY 8 //接近
#define SENSOR_TYPE_GRAVITY 9 //重力
#define SENSOR_TYPE_LINEAR_ACCELERATION 10//线性加速度
#define SENSOR_TYPE_ROTATION_VECTOR 11//旋转矢量
实现下列getSensorList()方法来取得感应检测Sensor的值;
List<Sensor> sensors = sm.getSensorList(Sensor.TYPE_TEMPERATURE);
第一个参数:监听Sensor事件,第二个参数是Sensor目标种类的值,第三个参数是延迟时间的精度密度。延迟时间的精密度参数如下:
参数 |
延迟时间 |
SensorManager.SENSOR_DELAY_FASTEST |
0ms |
SensorManager.SENSOR_DELAY_GAME |
20ms |
SensorManager.SENSOR_DELAY_UI |
60ms |
SensorManager.SENSOR_DELAY_NORMAL |
200ms |
因为感应检测Sensor的服务是否频繁和快慢都与电池参量的消耗有关,同时也会影响处理的效率,所以兼顾到消耗电池和处理效率的平衡,设置感应检测Sensor的延迟时间是一门重要的学问,需要根据应用系统的需求来做适当的设置。
感应检测Sensor的硬件检测组件受不同的厂商提供。你可以采用Sensor的getVendor(),Sensor()的getName()和Sensor的getVeesrion()方法来取得 厂商的名称、产品和版本。
android重力感应系统的坐标系以屏幕的左下方为原点(【注意】2d编程的时候,是以屏幕左上方为原点的),箭头指向的方向为正。从-10到10,以浮点数为等级单位,想象一下以下情形:
手机屏幕向上(z轴朝天)水平放置的时侯,(x,y,z)的值分别为(0,0,10);
手机屏幕向下(z轴朝地)水平放置的时侯,(x,y,z)的值分别为(0,0,-10);
手机屏幕向左侧放(x轴朝天)的时候,(x,y,z)的值分别为(10,0,0);
手机竖直(y轴朝天)向上的时候,(x,y,z)的值分别为(0,10,0);
其他的如此类推,规律就是:朝天的就是正数,朝地的就是负数。利用x,y,z三个值求三角函数,就可以精确检测手机的运动状态了。
public class MainActivity extends Activity implements SensorEventListener { private static final String TAG = MainActivity.class.getSimpleName(); private SensorManager mSensorManager; private Sensor mSensor; private TextView textviewX; private TextView textviewY; private TextView textviewZ; private TextView textviewF; private int mX, mY, mZ; private long lasttimestamp = 0; Calendar mCalendar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textviewX = (TextView) findViewById(R.id.textView1); textviewY = (TextView) findViewById(R.id.textView3); textviewZ = (TextView) findViewById(R.id.textView4); textviewF = (TextView) findViewById(R.id.textView2); mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// TYPE_GRAVITY if (null == mSensorManager) { Log.d(TAG, "deveice not support SensorManager"); } // 参数三,检测的精准度 mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);// SENSOR_DELAY_GAME } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { if (event.sensor == null) { return; } if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { int x = (int) event.values[0]; int y = (int) event.values[1]; int z = (int) event.values[2]; mCalendar = Calendar.getInstance(); long stamp = mCalendar.getTimeInMillis() / 1000l;// 1393844912 textviewX.setText(String.valueOf(x)); textviewY.setText(String.valueOf(y)); textviewZ.setText(String.valueOf(z)); int second = mCalendar.get(Calendar.SECOND);// 53 int px = Math.abs(mX - x); int py = Math.abs(mY - y); int pz = Math.abs(mZ - z); Log.d(TAG, "pX:" + px + " pY:" + py + " pZ:" + pz + " stamp:" + stamp + " second:" + second); int maxvalue = getMaxValue(px, py, pz); if (maxvalue > 2 && (stamp - lasttimestamp) > 30) { lasttimestamp = stamp; Log.d(TAG, " sensor isMoveorchanged...."); textviewF.setText("检测手机在移动.."); } mX = x; mY = y; mZ = z; } } /** * 获取一个最大值 * * @param px * @param py * @param pz * @return */ public int getMaxValue(int px, int py, int pz) { int max = 0; if (px > py && px > pz) { max = px; } else if (py > px && py > pz) { max = py; } else if (pz > px && pz > py) { max = pz; } return max; } }
原理就是通过每次得到的x,y,z三轴的值,和下一次的值作比较,它们每个差值中绝对值最大的如果超过某一个阀值(自己定义),并且这种状态持续了x秒,我们就视为手机处于(颠簸)移动状态,当然这种判断肯定是不科学的,有时候也会产生误判,比较理想的场景就是:携带手机坐在公交上或是开车。
其它可供参考资料:
http://blog.csdn.net/zhandoushi1982/article/details/8591878
http://blog.csdn.net/ZhengZhiRen/article/details/5930451
http://blog.csdn.net/a345017062/article/details/6459643