• 传感器系统服务SensorManager
  • 光照传感器SensorTYPE_LIGHT
  • 用法
  • 实战简易光照探测器
  • 加速度传感器
  • 加速度传感器的用法
  • 实战微信摇一摇
  • 方向传感器
  • 用法以及被放弃不推荐使用
  • 推荐使用获取手机旋转方向和角度的用法
  • 实战简易指南针


传感器系统服务——SensorManager

Android 中每个传感器的用法其实都比较类似,真的可以说是一通百通了。首先第一步要获取到 SensorManager 的实例。

SensorManager senserManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);

SensorManager 是系统所有传感器的管理器,有了它的实例之后就可以调用 getDefaultSensor()方法来得到任意的传感器类型了。

Sensor sensor = senserManager.getDefaultSensor(Sensor.TYPE_LIGHT);

光照传感器——Sensor.TYPE_LIGHT

用法

1、获取光照传感器

Sensor sensor = senserManager.getDefaultSensor(Sensor.TYPE_LIGHT);

Sensor.TYPE_LIGHT 常量来指定传感器类型,此时的 Sensor 实例就代表着一个光照传感器

2、对传感器输出的信号进行监听——SensorEventListener(接口)

SensorEventListener listener = new SensorEventListener() {
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
    }
};

当传感器的精度发生变化时就会调用 onAccuracyChanged()方法,当传感器监测到的数值发生变化时就会调用 onSensorChanged()方法。可以看到 onSensorChanged()方法中传入了一个 SensorEvent 参数,这个参数里又包含了一个 values 数组,所有传感器输出的信息都是存放在这里的。

3、注册 SensorEventListener

需要调用 SensorManager 的 registerListener()方法来注册 SensorEventListener才能使其生效,registerListener()方法接收三个参数,第一个参数就是 SensorEventListener 的实例,第二个参数是 Sensor 的实例,这两个参数我们在前面都已经成功得到了。第三个参数是用于表示传感器输出信息的更新速率,共有 SENSOR_DELAY_UI、 SENSOR_DELAY_NORMAL、SENSOR_DELAY_GAME 和 SENSOR_DELAY_FASTEST 这四种值可选,它们的更新速率是依次递增的。

senserManager.registerListener(listener, senser, SensorManager.SENSOR_DELAY_NORMAL);

4、退出释放
当程序退出或传感器使用完毕时,一定要调用 unregisterListener ()方法将使用的资源释放掉

sensorManager.unregisterListener(listener);

实战:简易光照探测器

public class MainActivity extends Activity {
    private SensorManager sensorManager;
    private TextView lightLevel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lightLevel = (TextView) findViewById(R.id.light_level);
        sensorManager = (SensorManager) getSystemService(Context. SENSOR_SERVICE);
        Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
        sensorManager.registerListener(listener, sensor, SensorManager. SENSOR_DELAY_NORMAL);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (sensorManager != null) {
            sensorManager.unregisterListener(listener);
        }
    }

    private SensorEventListener listener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            // values数组中第一个下标的值就是当前的光照强度
            float value = event.values[0];
            lightLevel.setText("Current light level is " + value + " lx");
        }
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
}

==》设置了监听,根据SensorEvent的values数组中下标第一位来获取当前检测到的光照强度。以勒克斯为单位,并且在最后程序退出时候释放。

加速度传感器

Android 中的加速度传感器则是提供了一种机制,使得我们能够在应用程序中获取到手机当前的加速度信息。

加速度传感器的用法

1、获取 Sensor 实例的时候要指定一个加速度传感器的常量

Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

2、获取输出信息——设置监听
加速度传感器输出的信息同样也是存放在 SensorEvent 的 values 数组中的,只不过此时的 values 数组中会有三个值,分别代表手机在 X 轴、 Y 轴和 Z 轴(0,1,2)方向上的加速度信息。

!!!由于地心引力的存在,你的手机无论在世界上任何角落都会有一个重力加速度,这个加速度的值大约是 9.8m/s 2 。当手机平放的时候,这个加速度是作用在 Z 轴上的,当手机竖立起来的时候,这个加速度是作用在 Y 轴上的,当手机横立起来的时候,这个加速度是作用在 X 轴上的。

实战——微信摇一摇

1、主体逻辑
检测手机在 X 轴、Y 轴和 Z 轴上的加速度,当达到了预定值的时候就可以认为用户摇动了手机,从而触发摇一摇的逻辑。

2、预设值
由于重力加速度的存在,即使手机在静止的情况下,某一个轴上的加速度也有可能达到9.8m/s 2 ,因此这个预定值必定是要大于 9.8m/s 2 的。

private SensorEventListener listener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        // 加速度可能会是负值,所以要取它们的绝对值
        float xValue = Math.abs(event.values[0]);
        float yValue = Math.abs(event.values[1]);
        float zValue = Math.abs(event.values[2]);
        if (xValue > 15 || yValue > 15 || zValue > 15) {
            // 认为用户摇动了手机,触发摇一摇逻辑
            Toast.makeText(MainActivity.this, "摇一摇", Toast.LENGTH_SHORT).show();
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
};

3、优化
比如说控制摇一摇的触发频率,使它短时间内不能连续触发两次等。

方向传感器

方向传感器的使用场景要比其他的传感器更为广泛,它能够准确地判断出手机在各个方向的旋转角度
使用场景:指南针、地平仪、赛车游戏等。

用法(以及被放弃,不推荐使用)

1、获取sensor

Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

2、获取传感器输出值——设置监听
也是会得到X、Y、Z轴三个方向上的旋转角度。values[0]记录着手机围绕 Z 轴的旋转角度,values[1] 记录着手机围绕 X 轴的旋转角度,values[2] 记录着手机围绕 Y 轴的旋转角度。

推荐使用获取手机旋转方向和角度的用法

Android 获取手机旋转的方向和角度是通过加速度传感器和地磁传感器共同计算得出的,这也是 Android 目前推荐使用的方式。

1、获取对应的加速度传感器和地磁传感器并注册监听

Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sensorManager.registerListener(listener, accelerometerSensor,SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(listener, magneticSensor,SensorManager.SENSOR_DELAY_GAME);

由于方向传感器的精确度要求通常都比较高,这里我们把传感器输出信息的更新速率提高了一些,使用的是 SENSOR_DELAY_GAME。

2、监听函数处理,获取传感器输出信息

接下来在 onSensorChanged()方法中可以获取到 SensorEvent 的 values 数组,分别记录着加速度传感器和地磁传感器输出的值 。 然后将这两个值传入 SensorManager的getRotationMatrix()方法中就可以得到一个包含旋转矩阵的 R 数组。

SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);

其中第一个参数 R 是一个长度为 9 的 float 数组,getRotationMatrix()方法计算出的旋转数据就会赋值到这个数组当中。第二个参数是一个用于将地磁向量转换成重力坐标的旋转矩阵,通常指定为 null 即可。第三和第四个参数则分别就是加速度传感器和地磁传感器输出的values 值。

3、计算旋转数据
得到了 R 数组之后,接着就可以调用 SensorManager 的 getOrientation()方法来计算手机的旋转数据了

SensorManager.getOrientation(R, values);

values 是一个长度为 3 的 float 数组,手机在各个方向上的旋转数据都会被存放到这个数组当中。其中 values[0]记录着手机围绕着图 12.3 中 Z 轴的旋转弧度,values[1]记录着手机围绕 X 轴的旋转弧度,values[2]记录着手机围绕 Y 轴的旋转弧度。

注意这里计算出的数据都是以弧度为单位的,因此如果你想将它们转换成角度还需要调用如下方法:

Math.toDegrees(values[0]);

实战——简易指南针

其实指南针的实现原理并不复杂,我们只需要检测到手机围绕 Z 轴的旋转角度,然后对这个值进行处理就可以了。

1、布局:两张居中显示的图片,罗盘背景和指针

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView
        android:id="@+id/compass_img"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerInParent="true"
        android:src="@drawable/compass" />
    <ImageView
        android:id="@+id/arrow_img"
        android:layout_width="60dp"
        android:layout_height="110dp"
        android:layout_centerInParent="true"
        android:src="@drawable/arrow" />
</RelativeLayout>

活动显示

public class MainActivity extends Activity {
    private SensorManager sensorManager;
    private ImageView compassImg;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        compassImg = (ImageView) findViewById(R.id.compass_img);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener(listener,magneticSensor,SensorManager.SENSOR_DELAY_GAME);
        sensorManager.registerListener(listener, accelerometerSensor,SensorManager.SENSOR_DELAY_GAME);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (sensorManager != null) {
            sensorManager.unregisterListener(listener);
        }
    }

    private SensorEventListener listener = new SensorEventListener() {
        float[] accelerometerValues = new float[3];
        float[] magneticValues = new float[3];
        private float lastRotateDegree;

        @Override
        public void onSensorChanged(SensorEvent event) {
            // 判断当前是加速度传感器还是地磁传感器
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                // 注意赋值时要调用clone()方法
                accelerometerValues = event.values.clone();
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                // 注意赋值时要调用clone()方法
                magneticValues = event.values.clone();
            }
            float[] R = new float[9];
            float[] values = new float[3];
            SensorManager.getRotationMatrix(R, null, accelerometerValues,magneticValues);
            SensorManager.getOrientation(R, values);
            // 将计算出的旋转角度取反,用于旋转指南针背景图
            float rotateDegree = -(float) Math.toDegrees(values[0]);
            if (Math.abs(rotateDegree - lastRotateDegree) > 1) {
                RotateAnimation animation = new RotateAnimation(lastRotateDegree, rotateDegree,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
                animation.setFillAfter(true);
                compassImg.startAnimation(animation);
                lastRotateDegree = rotateDegree;
            }
            Log.d("MainActivity", "value[0] is " + Math.toDegrees(values[0]));
        }
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
}

在 onCreate()方法中我们分别获取到了加速度传感器和地磁传感器的实例,并给它们注册了监听器。然后在 onSensorChanged()方法中进行判断,如果当前 SensorEvent 中包含的是加速度传感器,就将 values 数组赋值给accelerometerValues 数组,如果当前 SensorEvent 中包含的是地磁传感器,就将 values 数组赋值给 magneticValues 数组。注意在赋值的时候一定要调用一下 values 数组的 clone()方法,不然 accelerometerValues 和 magneticValues 将会指向同一个引用。

接下来我们分别创建了一个长度为 9 的 R 数组和一个长度为 3 的 values 数组,然后调用

getRotationMatrix()方法为 R 数组赋值,再调用 getOrientation()方法为 values 数组赋值,这时values 中就已经包含手机在所有方向上旋转的弧度了。其中 values[0]表示手机围绕 Z 轴旋转的弧度,这里我们调用 Math.toDegrees()方法将它转换成角度,并打印出来.

Android如何调用skia android如何调用系统指南针_加速度传感器