Android开发高级进阶——传感器

Android系统提供了对传感器的支持,如果手机设备的硬件提供了这些传感器,Android应用可以通过传感器来获取设备的外界条件,包括手机设备的运行状态、当前摆放方向、外界的磁场、温度和压力等。Android系统提供了驱动程序去管理这些传感器硬件,当传感器感知到外部环境发生改变时,Android系统负责管理这些传感器数据。

一. Android中11中常见的传感器


  1. 加速度传感器:SENSOR_TYPE_ACCELEROMETER
  • 磁力传感器:SENSOR_TYPE_FIELD
  • 方向传感器:SENSOR_TYPE_ORIENTATION
  • 陀螺仪传感器:SENSOR_TYPE_GYROSCOPE
  • 光线感应传感器:SENSOR_TYPE_LIGHT
  • 压力传感器:SENSOR_TYPE_PRESSURE
  • 温度传感器:SENSOR_TYPE_TEMPERATURE
  • 接近传感器:SENSOR_TYPE_PROXIMITY
  • 重力传感器:SENSOR_TYPE_GRAVITY
  • 线性加速度传感器:SENSOR_TYPE_LINEAR_ACCELERATION
  • 旋转矢量传感器:SENSOR_TYPE_ROTATION_VECTOR

二. 使用传感器


使用传感器的步骤分为5步:

  1. 获取SensorManager对象 调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象,SensorManager对象代表系统的传感器管理服务。
  2. 获取Sensor对象 调用SensorManager的getDefaultSensor(int type)方法获取指定类型的传感器。
  3. 注册Sensor对象 在Activity的onResume()方法中调用SensorManager的registerListener()方法为指定的传感器注册监听器,程序通过实现监听器即可获取传感器传来的数据。
  4. 重写onAccuracyChanged,onSensorChanged方法 当传感器的精度和数据发送变化时,在这两个方法中做相应的操作。
  5. 注销Sensor对象 在Activity的onPause()方法中调用SensorManager的unregisterListener()方法注销指定的传感器监听器。

SensorManager提供的注册传感器的方法为registerListener(SensorEventListener listener, Sensor sensor, int rate),该方法的三个参数说明如下:

  • listener:监听传感器事件的监听器。该监听器需要实现SensorEventListener接口。
  • sensor:传感器对象。
  • rate:指定获取传感器数据的频率。rate有以下几个频率值:
    • SensorManager.SENSOR_DELAY_FASTEST:最快。延迟最小,只有特别依赖于传感器数据的应用推荐采用这种频率,这种模式可能造成手机电量大量消耗。
    • SensorManager.SENSOR_DELAY_GAME:适合游戏的频率。一般有实时性要求的应用适合使用这种频率。
    • SensorManager.SENSOR_DELAY_NORMAL:正常频率。一般对实时性要求不是特别高的应用适合使用这种频率。
    • SensorManager.SENSOR_DELAY_UI:适合普通用户界面的频率。这种模式比较省电,而且系统开销也很小,但延迟较大。

三. 读取传感器数据


在onSensorChanged(SensorEvent event)方法中有一个参数event,通过event可以获取传感器的类型以及传感器的数据。

  • 获取传感器的类型:event.sensor.getType()
  • 获取传感器的数据:event.values[i],i为0,1,2...,不同传感器,event.values[i]对应的数据不同,下面以加速度传感器为例,解释values[i]的含义。
* <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER
     * Sensor.TYPE_ACCELEROMETER}:</h4> All values are in SI units (m/s^2)
     * <ul>
     * <li> values[0]: Acceleration minus Gx on the x-axis </li>
     * <li> values[1]: Acceleration minus Gy on the y-axis </li>
     * <li> values[2]: Acceleration minus Gz on the z-axis </li>
     * </ul>
     * <p>
     * A sensor of this type measures the acceleration applied to the device
     * (<b>Ad</b>). Conceptually, it does so by measuring forces applied to the
     * sensor itself (<b>Fs</b>) using the relation:
     * </p>
     * <b><center>Ad = - &#8721;Fs / mass</center></b>
     * <p>
     * In particular, the force of gravity is always influencing the measured
     * acceleration:
     * </p>
     * <b><center>Ad = -g - &#8721;F / mass</center></b>
     * <p>
     * For this reason, when the device is sitting on a table (and obviously not
     * accelerating), the accelerometer reads a magnitude of <b>g</b> = 9.81
     * m/s^2
     * </p>
     * <p>
     * Similarly, when the device is in free-fall and therefore dangerously
     * accelerating towards to ground at 9.81 m/s^2, its accelerometer reads a
     * magnitude of 0 m/s^2.
     * </p>
     * <p>
     * It should be apparent that in order to measure the real acceleration of
     * the device, the contribution of the force of gravity must be eliminated.
     * This can be achieved by applying a <i>high-pass</i> filter. Conversely, a
     * <i>low-pass</i> filter can be used to isolate the force of gravity.
     * </p>
     * <pre class="prettyprint">
     *     public void onSensorChanged(SensorEvent event)
     *     {
     *          // alpha is calculated as t / (t + dT)
     *          // with t, the low-pass filter's time-constant
     *          // and dT, the event delivery rate
     *          final float alpha = 0.8;
     *          gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
     *          gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
     *          gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
     *          linear_acceleration[0] = event.values[0] - gravity[0];
     *          linear_acceleration[1] = event.values[1] - gravity[1];
     *          linear_acceleration[2] = event.values[2] - gravity[2];
     *     }
     * </pre>
     * <p>
     * <u>Examples</u>:
     * <ul>
     * <li>When the device lies flat on a table and is pushed on its left side
     * toward the right, the x acceleration value is positive.</li>
     * <li>When the device lies flat on a table, the acceleration value is
     * +9.81, which correspond to the acceleration of the device (0 m/s^2) minus
     * the force of gravity (-9.81 m/s^2).</li>
     * <li>When the device lies flat on a table and is pushed toward the sky
     * with an acceleration of A m/s^2, the acceleration value is equal to
     * A+9.81 which correspond to the acceleration of the device (+A m/s^2)
     * minus the force of gravity (-9.81 m/s^2).</li>
     * </ul>

从加速度传感器源代码中可以看出,values[0]表示x轴上的加速度,values[1]表示y轴上的加速度,values[2]表示z轴上的加速度。

四. 针对是否有传感器功能优化


因为并非所有手机都支持所有传感器,不用系统引入的传感器不同,所以在使用之前有必要判断一下,、从而提高性能。

判断是否有传感器有两种方法:

  1. 运行时检测
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
if (sensor != null){
          //传感器存在
}else{
          //传感器不存在
}
  1. 使用Android Market过滤器来限定目标设备必须带有指定传感器配置。
<use-feature 
       name = "android.hardware.sensor.orientation"
       android:required = "true"/>

五. 方向传感器小Demo


利用方向传感器,界面中的图片向手机旋转的反方向旋转。代码如下:

public class MainActivity extends AppCompatActivity implements SensorEventListener{

    private ImageView mIvSensor;
    private Sensor mSensor;
    private SensorManager mSensorManager;
    private float mDegress = 0f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mIvSensor = (ImageView) findViewById(R.id.iv_sensor);

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_UI); //rate suitable for the user interface
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ORIENTATION){
            float degree = - event.values[0];
            RotateAnimation rotateAnimation = new RotateAnimation(mDegress, degree, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            rotateAnimation.setDuration(100);
            mIvSensor.startAnimation(rotateAnimation);
            mDegress = degree;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        //TODO:当传感器精度发生变化时
    }
}

演示效果:

orientation_sensor_demo.gif

六. 注意


  1. 别忘记注销。
  2. 不要阻塞onSensorChanged方法。
  3. 避免使用过时的方法或传感器类型。
  4. 在使用前先验证传感器是否存在。
  5. 谨慎选择传感器延时。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏安恒信息

假WiFi15分钟可盗取信息 网银被盗6万剩500块

近日,@央视新闻等多家权威媒体官方微博曝光,称一种利用假冒商场、快餐店的免费WiFi的骗术正在流行,通过这种方法,用户手机中的网银可以很轻易地...

3657
来自专栏IT大咖说

一年一度的每周5晚程序员段子又来了

程序员设计的版本号,一般会从1.0开始,然后,1.1、1.2、1.3……1.9,接下来的版本号会是1.10、1.11、1.12……于是有一天,在你的面前放着1....

802
来自专栏镁客网

三星Note 5外观大曝光,安兔兔跑分成绩不错

1655
来自专栏机器人网

干货教程:教你DIY一个萌蠢可爱的机器鸟

这个名叫RoboBrrd的鸟形机器人项目来自RobotGrrl,原文发布于Makezine。Makezine对本项目的难度评级为“适中”,制造耗时估计在3-20...

3456
来自专栏青蛙要fly的专栏

项目需求讨论 — 待机界面

一天,产品经理走过来搭了下我的肩膀。 产品经理:我要我们的APP有一个酷炫的待机界面。 我:可以啊,你要怎么样的界面? 产品经理:我也不知道啊,要么像手机...

652
来自专栏腾讯大讲堂的专栏

这个月起,在这座城市没带身份证也能住酒店了!

1816
来自专栏漏斗社区

专属| 940万名客户信息遭泄露

据报道,日前大型国际航空公司国泰航空披露,在今年3月发生的一次数据泄露事件中,该公司的940万名乘客的记录被盗,含有姓名、出生日期、住址等个人信息的护照信息也可...

1694
来自专栏阮一峰的网络日志

元数据(MetaData)

元数据是用来描述数据的数据(Data that describes other data)。单单这样说,不太好理解,我来举个例子。 下面是契诃夫的小说《套中人》...

32810
来自专栏Vamei实验室

程序员电邮札记

“Across the Great Wall, we can reach every corner in the world”。 这是1987年从中科院计算机所...

1827
来自专栏Spark学习技巧

为什么程序员对旧代码深恶痛绝?

最近有人问我,为什么软件开发者非常痛恨维护别人的代码?我思考了很久怎样回答这个问题,最后决定做一个简单的比喻。

791

扫码关注云+社区

领取腾讯云代金券