SensorManager
光照传感器
Android 中每个传感器的用法其实都比较类似,真的可以说是一通百通了。首先第一步要获取到 SensorManager 的实例
- SensorManager senserManager = (SensorManager)
- getSystemService(Context.SENSOR_SERVICE);
SensorManager 是系统所有传感器的管理器,有了它的实例之后就可以调用getDefaultSensor()方法来得到任意的传感器类型了
- Sensor sensor = senserManager.getDefaultSensor(Sensor.TYPE_LIGHT);
接下来我们需要对传感器输出的信号进行监听,这就要借助 SensorEventListener 来实现了。SensorEventListener 是一个接口,其中定义了 onSensorChanged()和onAccuracyChanged()这两个方法
- SensorEventListener listener = new SensorEventListener() {
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
- @Override
- public void onSensorChanged(SensorEvent event) {
- }
- };
当传感器的精度发生变化时就会调用 onAccuracyChanged()方法,当传感器监测到的数值发生变化时就会调用 onSensorChanged()方法。可以看到 onSensorChanged()
方法中传入了一个 SensorEvent 参数,这个参数里又包含了一个 values 数组,所有传感器输出的信息都是存放在这里的。下 面 我 们
还 需 要 调 用 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);
另外始终要记得, 当程序退出或传感器使用完毕时, 一定要调用 unregisterListener ()方法将使用的资源释放掉
- sensorManager.unregisterListener(listener);
代码:
- public class MainActivity extends Activity {
- SensorManager sensorManager;
- TextView light;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- light=(TextView) findViewById(R.id.textView1);
- sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE);
- Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
- sensorManager.registerListener(null, sensor, SensorManager.SENSOR_DELAY_NORMAL);
- }
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- if (sensorManager!=null) {
- sensorManager.unregisterListener(listener);
- }
- }
- private SensorEventListener listener=new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent arg0) {
- // TODO Auto-generated method stub
- // values数组中第一个下标的值就是当前的光照强度
- float value=arg0.values[0];
- light.setText("Current light level is"+value+"lx");
- }
- @Override
- public void onAccuracyChanged(Sensor arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- };
现在运行一下程序, 你将会在手机上看到当前环境下的光照强度, 根据所处环境的不同,显示的数值有可能是几十到几百勒克斯。而如果你使用强光来照射手机的话,就有可能会达到上千勒克斯的光照强度
加速度传感器:
第一, 获取 Sensor 实例的时候要指定一个加速度传感器的常量, 如下所示:
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
第二,加速度传感器输出的信息同样也是存放在 SensorEvent 的 values 数组中的,只不过此时的 values
数组中会有三个值,分别代表手机在 X 轴、Y 轴和 Z 轴方向上的加速度信息。X 轴、Y 轴、Z
轴在空间坐标系上的含义需要注意的是,由于地心引力的存在,你的手机无论在世界上任何角落都会有一个重力加速度,这个加速度的值大约是 9.8m/s
2 。当手机平放的时候,这个加速度是作用在 Z 轴上的,当手机竖立起来的时候,这个加速度是作用在 Y 轴上的,当手机横立起来的时候,这个加速度是作用在 X 轴上的
模仿微信摇一摇
- package com.example.yaoyiyao;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.app.Activity;
- import android.content.Context;
- import android.view.Menu;
- import android.widget.Toast;
- public class MainActivity extends Activity {
- private SensorManager sensorManager;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE);
- Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
- }
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- if (sensorManager!=null) {
- sensorManager.unregisterListener(sensorEventListener);
- }
- }
- private SensorEventListener sensorEventListener=new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent arg0) {
- // TODO Auto-generated method stub
- // 加速度可能会是负值,所以要取它们的绝对值
- float xValue=Math.abs(arg0.values[0]);
- float yValue=Math.abs(arg0.values[1]);
- float zValue=Math.abs(arg0.values[2]);
- if (xValue>15||yValue>15||zValue>15) {
- // 认为用户摇动了手机,触发摇一摇逻辑
- Toast.makeText(MainActivity.this, "摇一摇",
- Toast.LENGTH_SHORT).show();
- }
- }
- @Override
- public void onAccuracyChanged(Sensor arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- };
- }
方向传感器:
我们需要获取到一个用于表示方向传感器的 Sensor 实例
- Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
之后在 onSensorChanged()方法中通过 SensorEvent 的 values 数组,就可以得到传感器输出的所有值了。 方向传感器会记录手机在所有方向上的旋转角度
其中,values[0]记录着手机围绕 Z 轴的旋转角度,values[1] 记录着手机围绕 X 轴的旋转角度,values[2] 记录着手机围绕 Y 轴的旋转角度
看起来很美好是吗?但遗憾的是, Android早就废弃了Sensor.TYPE_ORIENTATION这种传感器类型,虽然代码还是有效的,但已经不再推荐这么写了。事实上,Android 获
取手机旋转的方向和角度是通过加速度传感器和地磁传感器共同计算得出的,这也是Android 目前推荐使用的方式。首先我们需要分别获取到加速度传感器和地磁传感器的实例,并给它们注册监听器
- 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。接下来在
onSensorChanged()方法中可以获取到 SensorEvent 的 values
数组,分别记录着加速度传感器和地磁传感器输出的值。然后将这两个值传入到 SensorManager的
getRotationMatrix()方法中就可以得到一个包含旋转矩阵的 R 数组
- SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);
其中第一个参数 R 是一个长度为 9 的 float 数组,getRotationMatrix()方法计算出的旋转数据就会赋值到这个数组当中。 第二个参数是一个用于将地磁向量转换成重力坐标的旋
转矩阵,通常指定为 null 即可。第三和第四个参数则分别就是加速度传感器和地磁传感器输出的 values 值。得到了 R 数组之后,接着就可以调用 SensorManager 的 getOrientation()方法来计算手机的旋转数据了
- SensorManager.getOrientation(R, values)
alues 是一个长度为 3 的 float 数组,手机在各个方向上的旋转数据都会被存放到这个数组当中。其中 values[0]记录着手机围绕着图 12.3 中 Z 轴的旋转弧度,values[1]记录
着手机围绕 X 轴的旋转弧度,values[2]记录着手机围绕 Y 轴的旋转弧度。注意这里计算出的数据都是以弧度为单位的, 因此如果你想将它们转换成角度还需要调用如下方法:
Math.toDegrees(values[0]);
简易指南针
- package com.example.zhinanzhen;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.app.Activity;
- import android.content.Context;
- import android.util.Log;
- import android.view.Menu;
- public class MainActivity extends Activity {
- private SensorManager sensorManager;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- sensorManager=(SensorManager) getSystemService(Context.SENSOR_SERVICE);
- //磁性传感器
- Sensor magmagneticSensor=sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
- //加速度传感器
- Sensor accelerometerSensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- sensorManager.registerListener(listener, magmagneticSensor, SensorManager.SENSOR_DELAY_GAME);
- }
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- if (sensorManager!=null) {
- sensorManager.unregisterListener(listener);
- }
- }
- private SensorEventListener listener=new SensorEventListener() {
- float[] accelerometerValues = new float[3];
- float[] magneticValues = new float[3];
- @Override
- public void onSensorChanged(SensorEvent arg0) {
- // TODO Auto-generated method stub
- // 判断当前是加速度传感器还是地磁传感器
- if (arg0.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
- // 注意赋值时要调用clone()方法
- accelerometerValues = arg0.values.clone();
- } else if (arg0.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
- // 注意赋值时要调用clone()方法
- magneticValues = arg0.values.clone();
- }
- float[] R = new float[9];
- float[] values = new float[3];
- SensorManager.getRotationMatrix(R, null, accelerometerValues,
- magneticValues);
- SensorManager.getOrientation(R, values);
- Log.d("MainActivity", "value[0] is " + Math.toDegrees(values[0]));
- }
- @Override
- public void onAccuracyChanged(Sensor arg0, int arg1) {
- // TODO Auto-generated method stub
- }
- };
- }
如果当前 SensorEvent 中包含的是加速度传感器,就将 values 数组赋值给 accelerometerValues 数组,如果当前 SensorEvent 中包含的是地磁传感器,就将
values 数组赋值给 magneticValues 数组。注意在赋值的时候一定要调用一下 values 数组的 clone()方法, 不然
accelerometerValues 和 magneticValues 将会指向同一个引用。接下来我们分别创建了一个长度为 9 的 R
数组和一个长度为 3 的 values 数组, 然后调用 getRotationMatrix()方法为 R 数组赋值,再调用
getOrientation()方法为 values 数组赋值,这时 values 中就已经包含手机在所有方向上旋转的弧度了。其中
values[0]表示手机围绕 Z 轴旋转的弧度,这里我们调用
Math.toDegrees()方法将它转换成角度,并打印出来。现在运行一下程序,并围绕 Z 轴旋转手机,旋转的角度就会源源不断地在
LogCat 中打印出来了
alues[0]的取值范围是- 180 度到 180 度,其中±180 度表示正南方向,0 度表示正北方向,- 90 度表示正西方向,90
度表示正东方向。虽然目前我们已经得到了这些数值,
但是想要通过它们来判断手机当前的方向显然是一件伤脑筋的事情,因此我们还要想办法将当前的方向直观地显示出来。毫无疑问,最直观的方式当然是通过罗盘和指针来进行显示了,那么下面我们就来继续完善
CompassTest这个项目。这里我事先准备好了两张图片 compass.png 和 arrow.png,分别用于作为指南针的
- <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);
- ⋯⋯
- }
- ⋯⋯
- 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[] values = new float[3];
- float[] R = new float[9];
- SensorManager.getRotationMatrix(R, null, accelerometerValues,
- magneticValues);
- SensorManager.getOrientation(R, values);
- // 将计算出的旋转角度取反,用于旋转指南针背景图
- float rotateDegree = -(float) Math.toDegrees(values[0]);
- if (Math.abs(rotateDegree - lastRotateDegree) > 1) {
- 第 12 章 Android 特色开发,使用传感器
- 473
- 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;
- }
- }
- ⋯⋯
- };
- }
这里首先我们在 onCreate()方法中获取到了 ImageView 的实例,它是用于显示指南针的背景图的。然后在 onSensorChanged()方法中使用到了旋转动画技术,我们创建了一
个 RotateAnimation
的实例,并给它的构造方法传入了六个参数,第一个参数表示旋转的起始角度,第二个参数表示旋转的终止角度,后面四个参数用于指定旋转的中心点。这里我们把从传感器中获取到的旋转角度取反,传递给
RotateAnimation,并指定旋转的中心点为指南针背景图的中心,然后调用 ImageView 的 startAnimation
()方法来执行旋转动画。好了,代码就是这么多,现在我们重新运行一下程序,然后随意旋转手机,指南针的背景图也会跟着一起转动
SensorManager的更多相关文章
- ANDROID_MARS学习笔记_S05_001_用SensorManager获取传感器
1. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...
- Android中SensorManager.getRotationMatrix函数原理解释
SensorManager是Android中的一个类,其有一个函数getRotationMatrix,可以计算出旋转矩阵,进而通过getOrientation求得设备的方向(航向角.俯仰角.横滚角). ...
- 获取Android设备的方向,Sensor和SensorManager实现手机旋转角度
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1009/425.html 带有g-sensor的Android设备上可通过API ...
- Android 内存泄漏的一些情况。
最近在维护代码,发现一个自定义View(这个View是在一个AsyncTask的工作线程doInBackground中新建的,在UI线程onPostExecute中添加进window中的)经常会泄漏内 ...
- android 6.0 高通平台sensor 工作机制及流程(原创)
最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...
- 【Android】[转] Android屏幕旋转使用OrientationEventListener的监听
说明 遇到一个奇葩的问题,我在使用onConfigChanged拦截屏幕的横竖屏旋转时,发现直接进行180度的横屏/竖屏转换居然没有反应!查找原因发现仅对landscape或者portrait状态有用 ...
- Android的系统服务一览
System_Server进程 运行在system server进程中的服务比较多,这是整个Android框架的基础 Native服务 SurfaceFlinger 这是framebuffer合成的服 ...
- Android开发之重力传感器
重力传感器与方向传感器的开发步骤类似,只要理清了期中的x,y,z的值之后就可以根据他们的变化来进行编程了,首先来看一副图 假设当地的重力加速度值为g 当手机正面朝上的时候,z的值为q,反面朝上的时候, ...
- Android内存泄漏
Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆的可能,所以写出来的 ...
随机推荐
- Linux top里面%CPU和us%的解释
我们有时会把%CPU和us%搞晕,也就是下图所示在top的时候查看cpu的信息. 这时有人会问:这两个CPU到底哪个是对的. 其实都是对的,只是表达的意思不一样. 官方解释如下 Cpu(s):34.0 ...
- EMQ 学习---MQTT消息QoS
MQTT发布消息QoS保证不是端到端的,是客户端与服务器之间的.订阅者收到MQTT消息的QoS级别,最终取决于发布消息的QoS和主题订阅的QoS. 客户端连接: 客户端完成TCP三次握手之后,还需要发 ...
- 一个Keygen,参考参考
看到一个Keygen,我觉得还可以,参考参考 //////////////////////////////////////////////////////////////////// //// key ...
- SIP/2.0 403 Forbidden(Invalid domain in From: header)
一.错误场景 FreeSWITCH通过网关和一台支持SIP的网关设备互联,一个呼叫发过去,收到这个错误. FreeSWITCH的地址是192.168.1.99. 网关设备的地址是192.168.1.2 ...
- 【BLE】CC2541之主机端读取特征值
本篇博文最后改动时间:2017年01月06日,11:06. 一.简单介绍 本文介绍怎样在SimpleBLECentralproject中,读取SimpleBLEPeripheralproject中的特 ...
- 逆向project第005篇:跨越CM4验证机制的鸿沟(下)
一.前言 本文是逆向分析CM4系列的最后一篇,我会将该游戏的序列号验证机制分析完成,进而编写出注冊码生成器. 二.分析第二个验证循环 延续上一篇文章的内容,来到例如以下代码处: 图1 上述代码并没有特 ...
- int、char、long各占多少字节数
Java基本类型占用的字节数:1字节: byte , boolean2字节: short , char4字节: int , float8字节: long , double 编码与中文:Unicode/ ...
- Jmeter测试带加密参数的接口
在做接口测试时,很多时候我们都会碰到带有加密参数的接口,这种接口一般来讲都会有统一的加密方法,找开发要就好,Jmeter怎么去测呢 1.整体结构如下所示: 2.操作步骤 (1)将加密方法打成jar包放 ...
- systemd启动多实例
最近用了centos7,启动管理器用的是systemd,感觉很好玩. 1.开机自动启动 新建一个service文件放到/usr/lib/systemd/system/ 比如: [Unit] Descr ...
- [每天一个Linux小技巧] 查看时钟源精度
$ dmesg | grep clock [0.000000] OMAP clocksource: GPTIMER1 at 24000000 Hz [0.000000] sched_clock: 3 ...