学习内容
Ø 传感器的基本概念
Ø Android中常见的传感器
Ø 如何在Android中开发传感器应用
能力目标
Ø 了解传感器的基本概念
Ø 掌握Android中常见的传感器
Ø 掌握Android环境下如何使用SensorSimulator进行传感器开发
Ø 熟练掌握加速度传感器的开发步骤
Ø 熟练掌握方向传感器的开发步骤
本章简介
Android是一个面向应用程序开发的丰富平台,它除了拥有许多具有吸引力的用户界面元素、数据管理和网络应用等优秀的功能之外,还提供了很多颇具特色的接口,比如对各种传感器的支持。Android应用可以通过传感器来获取设备的外界条件,包括手机设备的运行状态、当前摆放方向、外界的磁场、温度和压力等。通过在Android应用中添加传感器,可以充分激发开发者、用户的想象力,可以开发出各种有特色、有创意的应用程序,比如电子软盘、水平仪等。在本节中我们首先对传感器的基本概念进行了简要的介绍,之后通过一系列的具体案例给大家讲解Android中传感器开发的具体知识。
核心技能部分
传感器指的是能感受规定的被测量并按照一定的规律转换成可用输出信号的器件或装置,它通常由敏感元件和转换元件组成(国家标准GB7665-87对传感器的定义)。具体来说,传感器是一种检测装置,能感受被测量的信息,并能将检测到的信息按照一定的规律变换成为电信号或其它形式的信息输出,以满足信息的传输、处理、存储、显示、记录和控制等要求,它在自动检测和自动控制领域有很重要的应用。
自从苹果公司在2007年发布第一代iPhone以来,以前看似和手机不挨边儿的传感器也逐渐成为手机硬件的重要组成部分。使用过智能手机的用户会发现通过将手机横向或纵向放置,屏幕会随着手机位置的不同而改变方向,这种功能就是使用重力感应器实现的。除了重力感应器外,还有很多其它类型的传感器被应用到手机中,例如磁场传感器、方向传感器、温度传感器、压力传感器等。Android系统默认提供了对各种传感器的支持,它通过驱动程序管理这些传感器,当传感器感知到外部环境发生改变时,Android系统就可以根据这些传感器数据做出相应的处理。
常见的传感器有:
Ø 磁场传感器(Magnetic Field):主要用于读取手机设备外部的磁场强度,即使周围没有任何直接的磁场,手机设备也始终会处于地球磁场中,随着手机设备摆放状态的改变,周围的磁场的影响会在手机的X、Y、Z方向上发生改变。在Android中对应的常量值为:Sensor.TYPE_MAGNETIC_FIELD。
Ø 温度传感器(Temperature):用于获取手机设备所处环境的温度。在Android中对应的常量值为:Sensor.TYPE_TEMPERATURE。
Ø 光传感器(Light):用于获取手机设备所处环境的光的强度。在Android中对应的常量值为:Sensor.TYPE_LIGHT。
Ø 压力传感器(Pressure):用于获取手机设备所处环境的压力的大小。在Android中对应的常量值为:Sensor.TYPE_ORIENTATION。
Ø 方向传感器(Orientation):用于感应手机设备的摆放状态,它可以测量出手机顶端所处的方向。在Android中对应的常量值为:Sensor.TYPE_ORIENTATION。
Ø 加速度传感器/重力传感器:利用重力传感器可以测出手机在三维方向的加速度,通过重力传感器可以知道手机的摆放情况,比如知道手机与水平方向的倾角。在Android中对应的常量值为:Sensor.TYPE_ACCELEROMETER。
在Android系统中开发传感器应用十分简单,只需要通过简单的几步就可以实现非常复杂的功能,虽然在Android中开发传感器比较简单,但Android模拟器本身并没有提供传感器功能,在开发传感器相关的应用时,我们需要将程序部署到真机上才能看到效果。幸运的是,现在大家可以通过一个名为SensorSimulator工具模拟传感器的效果。Sensorsimulator由手机端和PC端两部分组成,当这两端的程序运行并建立连接之后,用户可以通过PC端的程序来模拟改变手机的传感数据。
大家可以去http://code.google.com/p/openintents/wiki/SensorSimulator 官网下载Sensorsimulator工具。在下载解压后的bin目录中看到一个jar文件、一个apk文件,其中那个jar文件是PC端程序,那个apk文件是手机端程序。
首先运行名为sensorsimulator-1.1.1.jar的jar文件,效果如下图5.1.1所示:
图5.1.1 Sensorsimulator 主界面
从图中可以看出,界面左上角是一个模拟手机位置的三维图形。中间部分上部可以通过滑杆来模拟手机的翻转、移动等操作,中间下半部分可以看出Sensorsimulator目前支持加速度传感器、方向传感器、磁场传感器、温度传感器、条形码阅读传感器、光传感器、近距离传感器(临近性传感器)等七种。右边还显示它支持电池模拟、发送GPS信号等。
启动模拟器,将名为SensorSimulatorSettings-1.1.1.apk的apk文件安装到模拟器上,安装成功后,运行程序,会在模拟器上看到图5.1.2所示的界面。
图5.1.2 手机端效果图
在图5.1.2所示的界面中依次填写上PC端程序的IP地址、监听端口,切换到Testing页面,单击Tab页里的Connect按钮,如图5.1.3所示,手机端就会与PC端进行连接,如果连接成功,在PC端左侧会看到如下图5.1.4所示的结果。
图5.1.3 测试连接状态
图5.1.4 连接成功
使用SensorSimulator开发传感器程序的具体步骤如下:
(1) 将SensorSimulator项目lib目录下的sensorsimulator-lib-1.1.1.jar导入Android项目。
(2) 在应用程序通过getSystemService()方法获取获取SensorManagerSimulator对象之后,调用connectSimulator()方法连接模拟器。
(3) 调用SensorManagerSimulator的getDefaultSensor()方法获取指定类型的传感器。
(4) 在Activity的onResume()方法中调用SensorManager的registerListener()为指定传感器注册监听器即可。程序通过实现监听器即可获取传感器传回来的数据。
(5) 为应用程序添加网络访问权限。
在Android中使用传感器要依赖于SensorEventListener接口,通过该接口可以监听传感器的各种事件。SensorEventListener接口的代码如下:
public interfaces SensorEventListener{
public void onSensorChanged(SensorEvent event);
public void onAccuracyChanged(Sensor sensor,int accuracy);
}
当传感器的值发生变化时,例如磁阻传感器的方向改变时会调用onSensorChanged()方法,当传感器的精度发生变化时会调用onAccuracyChanged()方法。
onSensorChanged()方法只有一个SensorEvent类型的参数event。其中SensorEvent类有一个values变量非常重要,该变量的类型是float[],但该变量最多只有3个元素,而且根据传感器的不同,values变量中元素所代表的含意也不同。
在解释values变量中元素的含义之前,我们先来看一下Android坐标系是如何定义x、y、z轴的。android使用惯性坐标系,所谓惯性坐标系是为了简化世界坐标而引入的一种新的坐标系。惯性坐标系的原点和物体坐标坐标系原点重合,但惯性坐标系的轴平行于世界坐标系的轴,其中:
Ø X轴的方向是沿着屏幕的水平方向从左向右。如果手机不是正方形的话,较短的边需要水平放置,较长的边需要垂直放置。
Ø Y轴的方向是从屏幕的左下角开始沿着屏幕的垂直方向指向屏幕的顶端
Ø 将手机平放在桌子上,Z轴的方向是从手机里指向天空。
下面分别介绍在方向传感器及加速度传感器中values变量的3个值的含义。
1. 方向传感器
在方向传感器中values变量的3个元素都表示度数,它们的含义如下 :
Ø values[0]:该值表示方位,也就是手机绕着Z轴旋转的角度。0表示正北(North)、90表示正东(East)、180表示正南(South)、270表示正西(West)。如果values[0]的值正好是这4个值,并且手机是水平放置的,那么手机的正前方就是这4个方向。可以利用这个特性来实现指南针。
Ø values[1]:该值表示倾斜度,或手机翘起的程度。当手机绕着X轴倾斜时该值会发生变化。values[1]的取值范围是-180~180。假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完全水平的,values[1]的值应该是0(由于很少有桌子是绝对水平的,因此,该值很可能不为0,但一般都是-5和5之间的某个值)。这时从手机顶部开始起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上),在这个过程中,values[1]会在0~-180之间变化,也就是说,从手机顶部抬起时,values[1]的值会逐渐变小,直到等于-180。如果从手机底部开始抬起,直到手机沿X轴旋转180度,这时values[1]会在0~180之间变化,也就是values[1]的值会逐渐增大,直到等于180。可以利用values[1]和下面将要介绍到的values[2]的值来实现实训任务3的手机倾斜度的测量
Ø values[2]:表示手机沿Y轴的滚动角度,取值范围在-90~90之间。假设将手机屏幕朝上水平放在桌面上,这里如果桌面是水平的,values[2]的值是0。将手机左侧逐渐抬起时,values[2]的值会逐渐变小,直到手机与桌面垂直时为-90;将手机右侧逐渐抬起时,values[2]的值会逐渐变大,直到手机与桌面垂直时为90。在垂直位置时继续向右或向左滚动,values[2]的值会继续在-90和90之间变化。
2. 加速度传感器:
该传感器的values变量的3个元素分别表示X、Y、Z轴的加速度。例如,水平放在桌面上的手机从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值,其它两个方向上值的变化与此类似。
在SensorSimulator中,要想使用相应的传感器,仅实现SensorEventListener接口是不够的,还需要注册相应的传感器。具体注册代码如下:
//获得传感器管理器
SensorManagerSimulator ma = SensorManagerSimulator.getSystemService (this,Context.SENSOR_SERVICE);
//获取指定的传感器
Sensor sensor = ma.getDefaultSensor (Sensor.TYPE_ACCELEROMETER);
//注册传感器
ma.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
getDefaultSensor()方法用来获取指定的传感器,参数为Android系统定义的常量值 。顾忌名思义,SensorManager/SensorManagerSimulator是所有传感器的一个综合管理类,包括了传感器的种类、采样率、精准度等 。尽管在Sensor类中注册了很多传感器常量,但要根据手机中实际的硬件配置来注册传感器。如果手机中没有相应的传感器硬件,就算注册了相应的传感器也不会起任何作用。
加速度传感器又叫重力传感器,它在移动设备中有很重要的应用,特别是在一些竞技类的游戏中。比如目前非常火爆的“3D超音速飞行”、“炫光重力平衡”等手机游戏都用到了重力感应器。
示例5.1
演示加速度传感器的使用。
利用SensorSimulator工具进行模拟测试,用程序获取到加速度传感器的各项模拟数据并显示在屏幕中的TextView中,熟悉加速度传感器的使用流程。
首先在主布局文件中提供一个TextView用来显示最终加速度的值。
编写Activity类,当手机移动触发SensorEventListener的onSensorChanged()事件时,将当前手机加速度在X、Y、Z三个方向上的分量值显示在手机屏幕上呈现给用户看。详细代码如下:
public class AccelerometerActivity extends Activity {
// 定义模拟器的Sensor管理器
private SensorManagerSimulator manager = null;
// 定义界面上的文本框组件
private TextView textView = null;
private SensorEventListener listener = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accelerometer);
// 获取程序界面的文本框组件
textView = (TextView) findViewById(R.id.textview);
// 获取传感器模拟器的传感器管理服务
manager = SensorManagerSimulator.getSystemService(this, SENSOR_SERVICE);
// 连接传感器模拟器
manager.connectSimulator();
}
@Override
protected void onResume() {
super.onResume();
//获取加速度传感器
Sensor sensor = manager.getDefaultSensor (Sensor.TYPE_ACCELEROMETER);
// 注册监听器,获取传感器的变化值
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop() {
// 必须取消注册,否则传感器会一直工作
manager.unregisterListener(listener);
super.onStop();
}
class SensorListener implements SensorEventListener {
@Override// 当传感器的值发生改变时回调该方法
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append("X方向上的加速度:").append(values[0]);
sb.append("\nY方向上的加速度:").append(values[1]);
sb.append("\nZ方向上的加速度:").append(values[2]);
textView.setText(sb.toString());
}
@Override// 当传感器精度改变时回调该方法
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}
程序中注册传感器的方法为:
boolean SensorManager.registerListener(SensorListener listener, int sensors, int rate)
Ø listener:监听器事件的监听器,该监听器需要实现SensorEventListener接口。
Ø sensors:传感器对象。
Ø rate:获取传感数据的频率,当应用程序请求特定的采样率时,其实只是对传感器子系统的一个建议,不能保证特定的采样可用。它支持的频率值参看表5-1-1。
表5-1-1 rate取值及含义
rate取值 |
含义 |
SENSOR_DELAY_FASTEST |
最快。延迟最小,会造成手机电量大量消耗,只有特别依赖于传感器数据的应用才推荐使用。 |
SENSOR_DELAY_GAME |
游戏常用频率,在一般实时性要求的应用上适合使用。 |
SENSOR_DELAY_NORMAL |
正常频率,一般实时性要求不是特别高的应用上适合使用。 |
SENSOR_DELAY_UI |
普通用户界面常用频率,此模式比较省电、系统开销较小,但延迟较大。适合在普通小程序中使用。 |
在本Activity类中需要注意的是,首先监听器的注册是放在onResume()方法中,也就是在桌面组件显示出来之前。其次是在onStop()方法中必须取消注册,否则传感器会一直工作,就会造成手机电量的不断消耗。
因为SensorSimulator案卷在Android模拟器的客户端需要和PC桌面端的服务端进行通信,因此本示例需要在功能清单文件中加入访问网络所需要的权限:
<uses-permission android:name="android.permission.INTERNET"/>
在运行程序之前先启动SensorSimulator的PC客户端和模拟器客户端程序,在两者之间建立连接,之后运行本示例程序,最后随机移动PC客户端左上角的图形模拟控制手机。某一时刻程序的运行效果如下图5.1.5所示。
图5.1.5 加速度传感器运行效果
开发真机上的传感器程序与使用SensorSimulator开发传感器程序的步骤及方法类似,区别在于:首先不需要引入外部的jar包,其次是使用SensorManager代替SensorManagerSimulator做为传感器管理服务器,把编程时所用到的Sensor、SensorEvent、SensorEventListener改为Android提供的类,而不再是由SensorSimulator提供的类,最后不再需要再进行网络授权。下面的Activity类就是对示例5.1进行修改后能在真机上运行的代码。
实例5.2
Android加速度传感器的使用,利用真机进行测试。
public class AccelerometerActivity2 extends Activity {
// 定义模拟器的Sensor管理器
private SensorManagerSimulator manager = null;
// 定义界面上的文本框组件
private TextView textView = null;
private SensorEventListener listener = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accelerometer);
// 获取程序界面的文本框组件
textView = (TextView) findViewById(R.id.textview);
// 获取传感器模拟器的传感器管理服务
manager = SensorManagerSimulator.getSystemService(this, SENSOR_SERVICE);
// 连接传感器模拟器
manager.connectSimulator();
}
@Override
protected void onResume() {
super.onResume();
// 为系统的加速度传感器注册监听器
manager.registerListener(listener, manager.getDefaultSensor
(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop() {
manager.unregisterListener(listener); // 取消注册
super.onStop();
}
class SensorListener implements SensorEventListener {
@Override// 当传感器的值发生改变时回调该方法
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append("X方向上的加速度:").append(values[0]);
sb.append("\nY方向上的加速度:").append(values[1]);
sb.append("\nZ方向上的加速度:").append(values[2]);
textView.setText(sb.toString());
}
@Override// 当传感器精度改变时回调该方法
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}
把该程序部署到手机上运行,程序的运行结果和图5.1.5类似。
上一节介绍了加速度传感器和相关知识及如何在模拟器中调试传感器,本节将对传感器的另一种应用——方向传感器进行介绍。方向传感器是使用最多的传感器之一,通过使用方向传感器,Android手机可以完成诸如指南针、水平尺等各种实用工具的功能,该传感器主要适应手机方位的变化,捕获的同样是三个数据,分别代表手机沿Yaw轴、Pitch轴、Roll轴转过的角度。
Yaw轴是三个轴中最简单的一个,其表示的方向是不变的,一直是重力加速度g的反方向,即一直是竖直向上的,与手机的姿态无关。
Pitch轴的方向并不是固定不变的,而是会随着手机沿Yaw轴旋转而改变,唯一不变的关系是该轴永远与Yaw轴成90度角。实际上Yaw轴与Pitch轴相当于绑到一起的一个90度支架,无论手机怎么旋转,其与Yaw轴的角度都为90度。如下图所示:
图5.1.6 Pitch轴原理
Roll轴是沿着手机屏幕向上的轴,在图5.1.6中可以看到,无论手机是何种姿态,Roll轴都是沿着手机的屏幕向上的,其方向是和手机绑定的。
实例:5.3
利用方向传感器实现一个能够在真机上正常运行的指南针软件。
首先编写主布局文件,在布局文件中提供一个id为imageView的ImageView组件用来显示十字形的指针图片
接下来编写Activity类,在该类中主要实现的功能是当手机方向发生变化时,利用动画技术旋转手机屏幕中中的指针图片。具体的代码如下:
public class CompassActivity extends Activity {
private ImageView imageView = null;
private SensorManager manager = null;
private SensorListener listener = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.compass);
listener = new SensorListener();
imageView = (ImageView) this.findViewById(R.id.imageView);
imageView.setKeepScreenOn(true);
manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
}
@Override
protected void onResume() {
Sensor sensor = manager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
super.onResume();
}
@Override
protected void onPause() {
manager.unregisterListener(listener);
super.onPause();
}
private final class SensorListener implements SensorEventListener {
private float predegree = 0;
public void onSensorChanged(SensorEvent event) {
float degree = event.values[0];
//以指南针图像中心为轴逆时针旋转degree度
RotateAnimation animation =
new RotateAnimation(predegree, -degree,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(250);//在150毫秒之内完成旋转动作
imageView.startAnimation(animation);//开始旋转图像
//保存旋转后的度数
predegree = -degree;
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}
本示例中用到的RotateAnimation的构造方法的定义及参数解释如下:
android.view.animation.RotateAnimation.RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
fromDegrees:旋转的开始角度。
toDegrees:旋转的结束角度。
pivotXType:X轴的伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
pivotXValue:X坐标的伸缩值。
pivotYType:Y轴的伸缩模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。
pivotYValue:Y坐标的伸缩值。
将程序部署到真机上运行,结果如下图5.1.7图所示。
图5.1.7 指南针
温度传感器也是应用较多的传感器,通过温度传感器可以开发出手机温度计等有趣的应用。
示例5.4
演示温度传感器的使用,利用SensorSimulator工具进行测试。
首先在主布局文件中提供一个TextView用来显示最终温度的值。
编写Activity类,实现对温度的监测。详细代码如下:
public class TemperatureActivity extends Activity {
private TextView textView = null;
private SensorManagerSimulator manager= null;
@Override
public void onCreate(Bundle savedInstanceState) {// 重写onCreate方法
super.onCreate(savedInstanceState);
setContentView(R.layout.main);// 设置当前的用户界面
textView = (TextView) findViewById(R.id.textView1);
manager = SensorManagerSimulator.getSystemService(this, SENSOR_SERVICE);
manager.connectSimulator(); // 与Simulator连接
}
private SensorEventListener mySensorListener = new SensorEventListener() {
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
@Override
public void onSensorChanged(SensorEvent event) {
textView.setText("当前的温度为:" + event.values[0]);// 将当前温度显示到TextView
}
};
@Override
protected void onResume() {// 重写的onResume方法
Sensor sensor = manager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
manager.registerListener(// 注册监听
mySensorListener, // 监听器SensorListener对象
sensor,// 传感器的类型为温度
SensorManager.SENSOR_DELAY_UI// 传感器事件传递的频度
);
super.onResume();
}
@Override
protected void onPause() {// 重写onPause方法
manager.unregisterListener(mySensorListener);// 取消注册监听器
super.onPause();
}
}
运行电脑端的SensorSimulator软件,调整工具中的参数使其能名模拟温度传感器,如图5.1.8所示。
图5.1.8 SensorSimulator工具温度测试支持
程序最终的运行结果如下图5.1.9所示。
图5.1.9 温度传感器测试结果
任务实训部分
训练技能点
加速度传感器
需求说明
在某些智能手机里面有这么一个功能,当我们在通话设置里面设置了“翻转静音”功能后,比如我们在上课或开会时,如果有来电,把手机翻转过来,背面向上,来电马上变静音了。本程序用到的知识非常简单,但功能非常实用。
实现思路
核心代码如下:
public class PhoneReversalActivity extends Activity {
private TextView textView;
private SensorManagerSimulator manager;
private SensorEventListener listener = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.phonereversal);
manager = (SensorManagerSimulator) SensorManagerSimulator
.getSystemService(this, Context.SENSOR_SERVICE);
manager.connectSimulator();
}
@Override
protected void onResume() {
super.onResume();
// 为系统的加速度传感器注册监听器
manager.registerListener(listener,
manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_ORIENTATION);
}
@Override
protected void onStop() {
// 取消注册
manager.unregisterListener(listener);
super.onStop();
}
class SensorListener implements SensorEventListener {
@Override
// 当传感器的值发生改变时回调该方法
public void onSensorChanged(SensorEvent event) {
switch (event.type) {
case SensorManager.SENSOR_ORIENTATION:
AudioManager audioManager =
(AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (event.values[2] < -130) {
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
} else {
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
textView.setText("角度:" + String.valueOf(event.values[2]));
break;
}
}
@Override
// 当传感器精度改变时回调该方法
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
}
训练技能点
Ø 自定义TextView
Ø 加速度传感器
核心代码
public class AngleViewActivity extends Activity {
//声明一个SensorManager管理传感器,一个自定义的类MyView,在myView中绘制自己想要的图像
private SensorManager manager;
private MyView myView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实例化SensorManager
manager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
//DisplayMetrics用于获取屏幕大小,再传递给myView方便绘制图形界面;
DisplayMetrics display = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(display);
//构造一个MyView,display.widthPixels是当前屏幕的宽度,display.heightPixels是当前屏幕的高度
myView = new MyView(this, display.widthPixels, display.heightPixels);
setContentView(myView);
}
//在onResume(),onPause()中注册和解除监听器
@Override
protected void onResume() {
super.onResume();
manager.registerListener(myView,
manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
manager.unregisterListener(myView);
Log.i("unregister", "ok");
super.onStop();
}
}
//自定义的类MyView 因为要感应传感器所以实现SensorEventListener。
class MyView extends View implements SensorEventListener {
//float x = 0;
//float y = 0;
//z轴上的值是我们所需要的,z轴就是垂直于水平面的方向,当你水平放置手机是它的数值为10,当你垂直放置时它就为0.
float z = 0;
private float width;
private float height;
Paint p ;
public MyView(Context context) {
super(context);
}
public MyView(Context context, float width, float height) {
super(context);
this.width = width;
this.height = height;
//得到一支画笔,设置基本属性
p = new Paint();
p.setStyle(Paint.Style.STROKE);
}
//在onDraw()方法中才是我们真正要画的东西,也就是真正显示在屏幕上的图像
@Override
protected void onDraw(Canvas canvas) {
//首先绘制一张背景图片,图片是事先PS好的一张背景图。canvas就是画布的意思,我们需要用画笔 p 在画布canvas上画画。
canvas.drawBitmap(
BitmapFactory.decodeResource(getResources(), R.drawable.circle),
0, 0, p);
p.setTextSize(50); //画背景后还要画文字,再对画笔进行设置。
//所画的文字就是实际测得的角度,在这之前需要对z值进行转化也就是todegree()方法。
canvas.drawText(todegree(z) + "°", width / 2 - 20, height / 2, p);
//画完后再画一个圆圈,这个圆圈随着角度变化而变大变小。
p.setColor(Color.RED);
p.setStrokeWidth(2);
canvas.drawCircle(width / 2, height / 2, 20 * z, p);
}
//如何把当前加速度的值转化为当前角度值呢?这需要一定的硬件基础才能明白其中的原理,不懂得同学可以看一些加速度传感器方面的书,关于加速度
//传感器还有很多应用,比如速度的测量,位移的测量,这就需要更加复杂的算法了,这里就不再介绍
private String todegree(float zz) {
//首先判断加速度的值是否大于10,小于-10,这是因为在运动过程中加速是不稳定的,而我们要测的是在静止状态下的稳定值。
if (zz > 10)
zz = 10;
else if (zz < -10) {
zz = -10;
double r = Math.acos(zz / 10); //求出倾斜角度的弧度值。
int degree = (int) (r * 180 / Math.PI); //然后将弧度值转化为角度值
return String.valueOf(degree); //最后返回该角度值
}
@Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
z = event.values[2]; //获得z轴的加速度值
}
invalidate(); //调用此方法进行重绘
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
巩固练习
一、简答题
1. 列举Android中常见的传感器及其对应的常量:
2. 简述开发真机上的传感器程序的步骤:
二、上机练习
使用方向传感器开发一个能够在真机上运行的水平仪。