Android对方向感应器的封装调用
Android自动的SensorManager使用起来已经很方便,但由于一些情况我们希望对其中的功能进行封装:
- 只使用个别的sensor,功能相对单一
- 要对sensor返回的raw data进行算法处理方可使用
- 程序中多处频繁调用禁用sensor的数据
由于项目需要在很多页面调用手机的方向信息,故而对sensor的方向感应器进行简单的封装,源码如下:
package com.weicheche.android.service; import java.util.ArrayList; import com.****.android.bean.ApplicationContext; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.SystemClock; /** * * @ClassName: OrientationService * @Description: TODO(对android SDk自带的方向感应器进行封装) * @author xuyong yxy8023@gmail.com * @date 2014年7月14日 上午2:24:10 */ public class OrientationService implements SensorEventListener { /* * 对于想要监听方向变化的类,需要继承实现这个接口 */ public static abstract interface OrientationListener{ public abstract void onOrientationChanged(float orientatoin); } protected final Handler mHandler = new Handler(); private SensorManager sensorManager; private Sensor mOrientationSensor; private float mTargetDirection = 0; private ArrayList<OrientationListener> listenerList = new ArrayList<OrientationListener>(); private long delayMillis = 20; public OrientationService() { // TODO Auto-generated constructor stub init(); } /** * * @Title: registerListener * @Description: TODO(将需要监听方向变化的类注册到OrientationService里,service中的sensor自动打开) * @param listener * @throws * @date 2014年7月14日 上午2:29:26 * Xuyong */ public void registerListener(OrientationListener listener){ listenerList.add(listener); if(1 == listenerList.size()){ // 刚刚有新的listener加入的时候打开方向感应器并启动更新线程 startService(); mHandler.postDelayed(mCompassViewUpdater, delayMillis); // delayMillis毫秒执行一次方向更新 } } /** * @Title: unregisterListener * @Description: TODO(再activity pause或者销毁时,讲listener从service移除,service会根据情况自动停止方向感应器的工作) * @param listener * @throws * @date 2014年7月14日 上午2:30:45 * Xuyong */ public void unregisterListener(OrientationListener listener){ if((listenerList.remove(listener)) && 0 == listenerList.size()){ // 如果成功移除listener后导致没有任何listener监听方向变化,暂停方向感应器 stopService(); } } /** * @Title: setDelayMillis * @Description: TODO(设置更新时间间隔,不得低于10ms) * @param delayMillis * @throws * @date 2014年7月14日 上午2:34:10 * Xuyong */ public void setDelayMillis(long delayMillis){ if(delayMillis>10){ this.delayMillis = delayMillis; } } /** * @Title: onDestory * @Description: TODO(移除所有的监听类,并停止方向感应器) * @throws * @date 2014年7月14日 上午2:34:46 * Xuyong */ public void onDestory(){ listenerList.clear(); stopService(); } /** * @Title: init * @Description: TODO(初始化方向感应器) * @throws * @date 2014年7月14日 上午12:36:53 * Xuyong */ @SuppressWarnings("deprecation") private void init(){ sensorManager = (SensorManager) ApplicationContext.getInstance().getContext().getSystemService(android.content.Context.SENSOR_SERVICE); try { mOrientationSensor = sensorManager.getSensorList( Sensor.TYPE_ORIENTATION).get(0); } catch (Exception e) { // TODO: handle exception mOrientationSensor = null; } } private void stopService(){ if (mOrientationSensor != null && sensorManager != null) { sensorManager.unregisterListener(this); } } private void startService(){ if (mOrientationSensor != null && sensorManager != null) { sensorManager.registerListener(this, mOrientationSensor, SensorManager.SENSOR_DELAY_GAME); } } /** * 这个是更新指南针旋转的线程,handler的灵活使用,每delayMillis毫秒检测方向变化值(这样的机制不太好,可能会出现线程阻滞) */ protected Runnable mCompassViewUpdater = new Runnable() { @Override public void run() { if (listenerList.size() > 0) {// 有监听的时候,传递下去,并且注意传入顺序为倒序,保证最近的层最先响应。 long startTime = SystemClock.uptimeMillis(); for(int i = listenerList.size()-1; i>=0; i--){ ((OrientationListener) listenerList.get(i)).onOrientationChanged(mTargetDirection); } // 由于线程阻滞,可能带来延时,通过时间控制来弥补 long endTime = SystemClock.uptimeMillis(); long delayTime = endTime - startTime; delayTime = (delayTime > delayMillis)? 2:(delayMillis-delayTime); mHandler.postDelayed(mCompassViewUpdater, delayTime); // 比定时器好 } } }; /* * no use currently */ @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } /** * @Title: onSensorChanged * @Description: TODO(直接调用SDK自带的API获取方向信息,以后需要修改为根据加速度和地磁数据的方向计算) * @param event * @throws * @date 2014年7月11日 下午4:52:36 * Xuyong */ @SuppressWarnings("deprecation") @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub switch (event.sensor.getType()) { // Note:改方法已经不鼓励使用,考虑在此处修改数据获取方向重新计算方向值 case Sensor.TYPE_ORIENTATION: float direction = event.values[SensorManager.DATA_X] * -1.0f; mTargetDirection = (direction + 720) % 360; // 赋值给全局变量,让指南针旋转 break; default: break; } } }
调用方法:
对任意activity,继承实现OrientationListener,在onResume和onPause中分别注册和注下销listener,代码如下:
1 public class xxxxActivity implements OrientationListener { 2 3 @Override 4 protected void onPause() { 5 super.onPause(); 6 ApplicationContext.getInstance().getOrientationService().unregisterListener(this); 7 } 8 9 @Override 10 public void onResume() { 11 super.onResume(); 12 ApplicationContext.getInstance().getOrientationService().registerListener(this); 13 } 14 15 @Override 16 public void onOrientationChanged(float orientatoin) { 17 // TODO Auto-generated method stub 18 adapter.setOrientation(orientatoin); 19 } 20 }