Android 光传感器开发详细教程

未经本人授权,不得转载!否则必将维权到底

最近我司产品提出了一个很常见的需求:App 通过手机光感器,获取当前的光线强度。根据光线强弱,弹窗提示用户是否切换白天/夜间模式。网上看了很多的博客,都没有解决我的问题。这个需求应该是挺常见的,故记录一下,供后人参考。

一、简介

光线感应器( Light Sensor ):光传感器主要用来检测手机周围光的强度,与其他传感器不同的是,该传感器监测手机周围光的强度,且单位为 lux。光传感器的开发与其他各种传感器的开发步骤基本相同,只是监测的是 Sensor.TYPE_LIGHT。如果学会了光感器的开发,开发其他的传感器则只需要改变监听器对象及注册监听的方法,然后根据每个人不同的业务需求,来修改后续的逻辑。

二、详细开发步骤(其他传感器基本类似)

1.通过 mContext.getSystemService() 得到传感器管理类
 SensorManager mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
2.监测手机上支持的传感器,如果手机没有光传感器,一定要做好容错!!!否则你的业务逻辑会出现空指针异常(其他的传感器同理,一定要先判断手机是否拥有这个传感器)
        //获取手机上支持的所有传感器
        List mList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor : mList) {
            L.d("KeithXiaoY","名字:" + sensor.getName());
            L.d("KeithXiaoY","type:" + sensorTypes.get(sensor.getType()) + "(" + sensor.getType() +")");
            L.d("KeithXiaoY","vendor:" + sensor.getVendor());
            L.d("KeithXiaoY","version:" + sensor.getVersion());
            L.d("KeithXiaoY","resolution:" + sensor.getResolution());
            L.d("KeithXiaoY","max range:" + sensor.getMaximumRange());
            L.d("KeithXiaoY","power:" + sensor.getPower());
        }
3.我的需求只需要光传感器,根据上一条打出来传感器的列表,光感器的 Type = 5,所以我做了如下判断:
        //获取手机上支持的传感器
        mList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor : mList) {
            if (Sensor.TYPE_LIGHT ==  sensor.getType()){
                mIsContains = true ; //这是一个 Boolean 值,true 代表有这个传感器、false 代表没有
                return;
            }
        }
4.下面就是要注册光传感器了
    /*  第三个参数是传感器数据更新数据的速度
          有以下四个值可选,他们的速度是递增的
          SENSOR_DELAY_UI
          SENSOR_DELAY_NORMAL
          SENSOR_DELAY_GAME
          SENSOR_DELAY_FASTEST*/
    public void registerSensor() {
        // 获得光线传感器
        if ( null != mSensorManager){
            Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
            if ( null != sensor && mIsContains) {
                mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
            }
        }

    }
5.现在可以监听传感器数据的变化了,我写了一个工具类,让其实现 SensorEventListener 接口,需要重写两个方法
public class LightSensorUtils implements SensorEventListener{
    //  onSensorChanged() 在传感器数值发生变化已经注册监听器时调用,其更新频率就是注册中的参数三。 对于光传感器,有效数值存放在 values[0] 中的,单位为SI lunx。光传感器通常位于上方(一般靠左侧), 除了前置摄像头外还有一个孔,一般就是它。遮盖会触发 onSensorChanged()
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
            L.d("KeithXiaoY",event.values[0] + "");
         // 下面就是每个人自己的逻辑了,根据拿到的 event.values[0] ,来做相应的逻辑。
        }
    }

    /*  onAccuracyChanged() 会在精度改变或在注册监听器时调用。
        accuracy分为4档,0(unreliable),1(low),2(medium),3(high)。注意0并不代表有问题,同时是传感器需要校准。 */
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
      //这个方法一般里面什么都不写
    }
}
6.上面是分步骤讲解,省略了不少代码,下面我写的光感器工具类的完整代码,注释很详细了…
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

import java.util.List;

/**
 * Created by KeithXiaoY on 2017/5/31.
 *
 * 光线传感器的类型常量是Sensor.TYPE_LIGHT。values数组只有第一个元素(values[0])有意义。表示光线的强度。最大的值是120000.0f
 * Android SDK将光线强度分为不同的等级,每一个等级的最大值由一个常量表示,这些常量都定义在SensorManager类中,代码如下:
 * public static final float LIGHT_SUNLIGHT_MAX =120000.0f;
 * public static final float LIGHT_SUNLIGHT=110000.0f;
 * public static final float LIGHT_SHADE=20000.0f;
 * public static final float LIGHT_OVERCAST= 10000.0f;
 * public static final float LIGHT_SUNRISE= 400.0f;
 * public static final float LIGHT_CLOUDY= 100.0f;
 * public static final float LIGHT_FULLMOON= 0.25f;
 * public static final float LIGHT_NO_MOON= 0.001f;
 * 上面的八个常量只是临界值,在实际使用光线传感器时要根据实际情况确定一个范围。
 * 例如,当太阳逐渐升起时,values[0] 的值很可能会超过 LIGHT_SUNRISE,
 * 当 values[0] 的值逐渐增大时,就会逐渐越过LIGHT_OVERCAST,而达到 LIGHT_SHADE。
 * 当然,如果天特别好的话,也可能会达到LIGHT_SUNLIGHT,甚至更高。
 */

public class LightSensorUtils implements SensorEventListener{
    private static final Object mLock = new Object();
    private static LightSensorUtils instance;
    private static Context mContext;

    private SensorManager mSensorManager;// 传感器管理器
    private List mList;
    private boolean mIsContains = false;
    private  Boolean isBright ;//true 代表亮      false 代表暗
    private final Float criticalValue = 40.0f;  //  40.0f 代表人视觉的亮暗临界值


    private LightSensorUtils() {
    }

    //需要用光感器的地方在 init 初始化 
    public void init(Context context) {
        mContext = context;
        mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
        //获取手机上支持的传感器
        mList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        for (Sensor sensor : mList) {
            if (Sensor.TYPE_LIGHT ==  sensor.getType()){
                mIsContains = true ;
                return;
            }
        }
    }


    public static LightSensorUtils getInstance() {
        if (instance == null) {
            synchronized (mLock) {
                if (instance == null) {
                    instance = new LightSensorUtils();
                }
            }
        }
        return instance;
    }

    /*  第三个参数是传感器数据更新数据的速度
          有以下四个值可选,他们的速度是递增的
          SENSOR_DELAY_UI
          SENSOR_DELAY_NORMAL
          SENSOR_DELAY_GAME
          SENSOR_DELAY_FASTEST*/
    public void registerSensor() {
        // 获得光线传感器
        if ( null != mSensorManager){
            Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
            if ( null != sensor && mIsContains) {
                mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
            }
        }

    }

    public void unRegisterSensor() {
        if ( null != mSensorManager){
            mSensorManager.unregisterListener(this);
        }

    }

    /*  onSensorChanged()在传感器数值发生变化已经注册监听器时调用,其更新频率就是注册中的参数三。
        对于光传感器,有效数值存放在values[0]中的,单位为SI lunx。
        光传感器通常位于上方(一般靠左侧), 除了前置摄像头外还有一个孔,一般就是它。遮盖会触发onSensorChanged()  */
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
            L.d("KeithXiaoY",event.values[0] + "");
            isBright = event.values[0] > criticalValue ? true : false ;//  40.0f 代表人视觉的亮暗临界值,我司定义 > 40.0f 为亮,<= 40.0f 为暗

 // 下面就是每个人自己的逻辑了,根据拿到的 event.values[0] ,我写了一个把光的亮度分为 8 级的方法。
//            getBrightString(event.values[0]);

        }
    }

//    private int getBrightString(float value) {
//        if (value >= LIGHT_SUNLIGHT_MAX) {
//            currentMode = 8 ;
//            return currentMode;
//        } else if (value > LIGHT_SUNLIGHT) {
//            currentMode = 7 ;
//            return currentMode;
//        } else if (value > LIGHT_SHADE) {
//            currentMode = 6 ;
//            return currentMode;
//        } else if (value > LIGHT_OVERCAST) {
//            currentMode = 5 ;
//            return currentMode;
//        } else if (value > LIGHT_SUNRISE) {
//            currentMode = 4 ;
//            return currentMode;
//        } else if (value > LIGHT_CLOUDY) {
//            currentMode = 3 ;
//            return currentMode;
//        } else if (value > LIGHT_FULLMOON) {
//            currentMode = 2 ;
//            return currentMode;
//        } else if (value > LIGHT_NO_MOON) {
//            currentMode = 1 ;
//            return currentMode;
//        } else {
//            currentMode = -1 ;
//            return currentMode;
//        }
//    }


    /* onAccuracyChanged()会在精度改变或在注册监听器时调用。
        accuracy分为4档,0(unreliable),1(low),2(medium),3(high)。
        注意0并不代表有问题,同时是传感器需要校准。 */

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }



    public Boolean getBright() {
        return  isBright;
    }
}

三、详细业务步骤(在 Activity 里面如何去用)

1.首先来到你监测光强度的具体页面,先初始化,这里 init() 传入的是 ApplicationContext,防止内存泄漏!!!
public class XXXActivity{
    private LightSensorUtils mLightSensorUtils;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.xxx_activity);
        //初始化光线传感器
        mLightSensorUtils = LightSensorUtils.getInstance();
        mLightSensorUtils.init(getApplicationContext());
    }

}
2.由于传感器是非常耗电的,所以在 onResume() 里面注册,在 onPause() 里面解除注册,这步千万别忘记了!!!
    @Override
    public void onResume() {
        super.onResume();
        mLightSensorUtils.registerSensor();
        Boolean isBright = mLightSensorUtils.getBright();
        L.d("KeithXiaoY","onResume方法中的isBright : "+ isBright);
        if (null != isBright){
            checkTheme();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        mLightSensorUtils.unRegisterSensor();
    }
3.这两步做完以后,就是执行大家自己的业务逻辑了,想必每个人的需求都不一样,我的具体需求就是上面 checkTheme() 方法
/*根据监听器时时返回的数据,我可以拿到当前的 isBright ,true 代表光线亮,false 代表光线暗,来弹窗提示用户是否需要切换模式 */
 public void checkTheme(){
     ...
     Boolean isBright = mLightSensorUtils.getBright();
     L.d("KeithXiaoY","白天模式isBright : "+ isBright);
     if (null != isBright){
         if (!isBright){
            SimpleDialogFragment.createBuilder(this, getSupportFragmentManager())
            .setMessage("同学您好,光线不足,切换到夜间模式吧")
            .setTitle(R.string.warm_tips)   
            .setPositiveButtonText(R.string.do_switch)
            .setNegativeButtonText(R.string.do_not_switch)
            .setRequestCode(REQ_SWITCH_TO_NIGHTLY).show();
     }else{
      ......
     }
}

四、结语

学会了一种传感器的使用方法后,其他传感器举一反三,相信以后再遇到传感器开发就没那么头疼了。真的写的超级详细了,应该是史上最详细吧~


本文原创发布于微信公众号「keithxiaoy」,编程、思维、成长、正能量,关注并回复「编程」、「阅读」、「Java」、「Python」等关键字获取免费学习资料

不要给自己的人生设限

你可能感兴趣的:(Android)