Android常用传感器用法一览(3)

时间:2020-12-18 01:08:18

Android 开发包标准有8个传感器:

  • Sensor.TYPE_ACCELEROMETER

o 加速度计 (X, Y, Z) m/s2

  • Sensor.TYPE_GYROSCOPE

o 陀螺仪 (X, Y, Z) degrees

  • Sensor.TYPE_LIGHT

o 光照 (single) lux

  • Sensor.TYPE_MAGNETIC_FIELD

o 磁力计 (X, Y, Z) microteslas

  • Sensor.TYPE_ORIENTATION

o 方位传感器 (X, Y, Z) degrees

  • Sensor.TYPE_PRESSURE

o 压力传感器 (single) kilopascals 测量加在手机设备上的压力

  • Sensor.TYPE_PROXIMITY

o 距离传感器 (single) meters 典型应用为接听电话时,根据光照,声音估计距离

  • Sensor.TYPE_TEMPERATURE

o 温度传感器 (single) degrees Celsius 电池温度,或是具体传感器温度,看具体实现

手机型号不同,硬件实现有所区别。

读取传感器代码如下:

Java代码

1 package com.ldq.sensor;

2

3 import java.util.List;

4

5 import android.app.Activity;

6 import android.hardware.Sensor;

7 import android.hardware.SensorManager;

8 import android.os.Bundle;

9 import android.widget.LinearLayout;

10 import android.widget.TextView;

11

12 public class ExSensor extends Activity {

13

14     private LinearLayout layout;

15

16     /** Called when the activity is first created. */

17     @Override

18     public void onCreate(Bundle savedInstanceState) {

19         super.onCreate(savedInstanceState);

20         setContentView(R.layout.main);

21         layout = (LinearLayout) findViewById(R.id.LinearLayout01);

22

23         SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

24         List<Sensor> list = sm.getSensorList(Sensor.TYPE_ALL);

25         TextView text = new TextView(this);

26         text.setText("传感器数量:" + list.size());

27         layout.addView(text);

28

29         TextView[] name = new TextView[list.size()];

30         for (int i = 0; i < list.size(); i++) {

31             name[i] = new TextView(this);

32             name[i].setText((i + 1) + " : " + list.get(i).getName());

33             layout.addView(name[i]);

34         }

35

36     }

37 }

Android 传感器功能

使用 Android 平台有一个很新颖的地方,那就是您可以在设备内部访问一些 “好工具”。过去,访问设备底层硬件的能力一度让移动开发人员感到非常棘手。尽管 Android Java 环境的角色仍然是您和设备的桥梁,但 Android 开发团队让许多硬件功能浮出了水面。该平台是一个开源平台,因此您可以*地编写代码实现您的任务。

如果尚未安装 Android,您可以 下载 Android SDK。您还可以 浏览 android.hardware 包的内容并参考本文的示例。android.media 包 包含了一些提供有用和新颖功能的类。

Android SDK 中包含的一些面向硬件的功能描述如下。

表 1. Android SDK 中提供的面向硬件的特性

特性

描述

android.hardware.Camera

允许应用程序与相机交互的类,可以截取照片、获取预览屏幕的图像,修改用来治理相机操作的参数。

android.hardware.SensorManager

允许访问 Android 平台传感器的类。并非所有配备 Android 的设备都支持 SensorManager 中的所有传感器,虽然这种可能性让人非常兴奋。(可用传感器的简介见下文)

android.hardware.SensorListener

在传感器值实时更改时,希望接收更新的类要实现的接口。应用程序实现该接口来监视硬件中一个或多个可用传感器。例如,本文中的 代码 包含实现该接口的类,实现后可以监视设备的方向和内置的加速表。

android.media.MediaRecorder

用于录制媒体样例的类,对于录制特定位置(比如婴儿保育)的音频活动非常有用。还可以分析音频片段以便在访问控件或安全应用程序时进行身份鉴定。例如,它可以帮助您通过声音打开门,以节省时间,不需要从房产经纪人处获取钥匙。

android.FaceDetector

允许对人脸(以位图形式包含)进行基本识别的类。不可能有两张完全一样的脸。可以使用该类作为设备锁定方法,无需记密码 — 这是手机的生物特征识别功能。

android.os.*

包含几个有用类的包,可以与操作环境交互,包括电源管理、文件查看器、处理器和消息类。和许多可移动设备一样,支持 Android 的电话可能会消耗大量电能。让设备在正确的时间 “醒来” 以监视感兴趣的事件是在设计时需要首先关注的方面。

java.util.Date
java.util.Timer
java.util.TimerTask

当测量实际的事件时,数据和时间往往很重要。例如,java.util.Date 类允许您在遇到特定的事件或状况时获取时间戳。您可以使用 java.util.Timer 和 java.util.TimerTask 分别执行周期性任务或时间点任务。

android.hardware.SensorManager 包含几个常量,这表示 Android 传感器系统的不同方面,包括:

传感器类型

方向、加速表、光线、磁场、临近性、温度等。

采样率

最快、游戏、普通、用户界面。当应用程序请求特定的采样率时,其实只是对传感器子系统的一个提示,或者一个建议。不保证特定的采样率可用。

准确性

高、低、中、不可靠。

SensorListener 接口是传感器应用程序的中心。它包括两个必需方法:

  • onSensorChanged(int sensor,float values[]) 方法在传感器值更改时调用。该方法只对受此应用程序监视的传感器调用(更多内容见下文)。该方法的参数包括:一个整数,指示更改的传感器;一个浮点值数组,表示传感器数据本身。有些传感器只提供一个数据值,另一些则提供三个浮点值。方向和加速表传感器都提供三个数据值。
  • 当传感器的准确性更改时,将调用 onAccuracyChanged(int sensor,int accuracy) 方法。参数包括两个整数:一个表示传感器,另一个表示该传感器新的准确值。

要与传感器交互,应用程序必须注册以侦听与一个或多个传感器相关的活动。注册使用 SensorManager 类的 registerListener 方法完成。本文中的 代码示例 演示了如何注册和注销 SensorListener。

记住,并非所有支持 Android 的设备都支持 SDK 中定义的所有传感器。如果某个传感器无法在特定的设备上使用,您的应用程序就会适当地降级。

传感器示例

样例应用程序仅监控对方向和加速表传感器的更改(源代码见 下载)。当收到更改时,传感器值在 TextView 小部件的屏幕上显示。图 1 展示了该应用程序的运行情况。

图 1. 监视加速和方向

使用 Eclipse 环境和 Android Developer Tools 插件创建的应用程序。(关于使用 Eclipse 开发 Android 应用程序的信息,请参见 参考资料。)清单 1 展示了该应用程序的代码。

清单 1. IBMEyes.java

package com.msi.ibm.eyes;

import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

import android.widget.TextView;

import android.hardware.SensorManager;

import android.hardware.SensorListener;

public class IBMEyes extends Activity implements SensorListener {

final String tag = "IBMEyes";

SensorManager sm = null;

TextView xViewA = null;

TextView yViewA = null;

TextView zViewA = null;

TextView xViewO = null;

TextView yViewO = null;

TextView zViewO = null;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// get reference to SensorManager

sm = (SensorManager) getSystemService(SENSOR_SERVICE);

setContentView(R.layout.main);

xViewA = (TextView) findViewById(R.id.xbox);

yViewA = (TextView) findViewById(R.id.ybox);

zViewA = (TextView) findViewById(R.id.zbox);

xViewO = (TextView) findViewById(R.id.xboxo);

yViewO = (TextView) findViewById(R.id.yboxo);

zViewO = (TextView) findViewById(R.id.zboxo);

}

public void onSensorChanged(int sensor, float[] values) {

synchronized (this) {

Log.d(tag, "onSensorChanged: " + sensor + ", x: " +

values[0] + ", y: " + values[1] + ", z: " + values[2]);

if (sensor == SensorManager.SENSOR_ORIENTATION) {

xViewO.setText("Orientation X: " + values[0]);

yViewO.setText("Orientation Y: " + values[1]);

zViewO.setText("Orientation Z: " + values[2]);

}

if (sensor == SensorManager.SENSOR_ACCELEROMETER) {

xViewA.setText("Accel X: " + values[0]);

yViewA.setText("Accel Y: " + values[1]);

zViewA.setText("Accel Z: " + values[2]);

}

}

}

public void onAccuracyChanged(int sensor, int accuracy) {

Log.d(tag,"onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);

}

@Override

protected void onResume() {

super.onResume();

// register this class as a listener for the orientation and accelerometer sensors

sm.registerListener(this,

SensorManager.SENSOR_ORIENTATION |SensorManager.SENSOR_ACCELEROMETER,

SensorManager.SENSOR_DELAY_NORMAL);

}

@Override

protected void onStop() {

// unregister listener

sm.unregisterListener(this);

super.onStop();

}

}

编写应用程序必须基于常见的活动,因为它只是利用从传感器获取的数据更新屏幕。在设备可能在前台执行其他活动的应用程序中,将应用程序构建为服务可能更加合适。

该活动的 onCreate 方法可以引用 SensorManager,其中包含所有与传感器有关的函数。onCreate 方法还建立了对 6 个 TextView 小部件的引用,您需要使用传感器数据值更新这些小部件。

onResume() 方法使用对 SensorManager 的引用通过 registerListener 方法注册传感器更新:

  • 第一个参数是实现 SensorListener 接口的类的实例。
  • 第二个参数是所需传感器的位掩码。在本例中,应用程序从 SENSOR_ORIENTATION 和 SENSOR_ACCELEROMETER 请求数据。
  • 第三个参数是一个系统提示,指出应用程序更新传感器值所需的速度。

应用程序(活动)暂停后,需要注销侦听器,这样以后就不会再收到传感器更新。这通过 SensorManager 的 unregisterListener 方法实现。惟一的参数是 SensorListener 的实例。

在 registerListener 和 unregisterListener 方法调用中,应用程序使用关键字 this。注意类定义中的 implements 关键字,其中声明了该类实现 SensorListener 接口。这就是要将它传递到 registerListener 和 unregisterListener 的原因。

SensorListener 必须实现两个方法 onSensorChange 和 onAccuracyChanged。示例应用程序不关心传感器的准确度,但关注传感器当前的 X、Y 和 Z 值。onAccuracyChanged 方法实质上不执行任何操作;它只在每次调用时添加一个日志项。

似乎经常需要调用 onSensorChanged 方法,因为加速表和方向传感器正在快速发送数据。查看第一个参数确定哪个传感器在发送数据。确认了发送数据的传感器之后,将使用方法第二个参数传递的浮点值数组中所包含的数据更新相应的 UI 元素。该示例只是显示这些值,但在更加高级的应用程序中,还可以分析这些值,比较原来的值,或者设置某种模式识别算法来确定用户(或外部环境)的行为。

Android传感器系统全解析

http://developer.51cto.com  2010-02-04 16:03  佚名  CSDN  我要评论(0)

在本文中,我们介绍了 Android传感器,在样例应用程序度量了方向和加速,以及使用 MediaRecorder 类与录制功能进行交互。

Android是一个灵活、有吸引力的平台,Google的Android 领域发展迅速,并且越来越发展的强大,下面的文章进行全面的介绍Android传感器和报告系统有关的应用程序架构。

应用程序(活动)暂停后,需要注销侦听器,这样以后就不会再收到传感器更新。这通过 SensorManager 的 unregisterListener 方法实现。惟一的参数是 SensorListener 的实例。在 registerListener 和 unregisterListener 方法调用中,应用程序使用关键字 this。注意类定义中的 implements 关键字。

其中声明了该类实现 SensorListener 接口。这就是要将它传递到 registerListener 和 unregisterListener 的原因。SensorListener 必须实现两个方法 onSensorChange 和onAccuracyChanged。示例应用程序不关心传感器的准确度。

但关注传感器当前的 X、Y 和 Z 值。onAccuracyChanged 方法实质上不执行任何操作;它只在每次调用时添加一个日志项。似乎经常需要调用 onSensorChanged 方法,因为加速表和方向传感器正在快速发送数据。查看第一个参数确定哪个传感器在发送数据。

确认了发送数据的传感器之后,将使用方法第二个参数传递的浮点值数组中所包含的数据更新相应的 UI 元素。该示例只是显示这些值,但在更加高级的应用程序中,还可以分析这些值,比较原来的值,或者设置某种模式识别算法来确定用户(或外部环境)的行为。

现在您已经了解了传感器子系统,接下来的部分将回顾一个在Android传感器上录制音频的代码样例。该样例运行在 DEV1 开发设备上。android.media 包包含与媒体子系统交互的类。使用 android.media.MediaRecorder 类进行媒体采样,包括音频和视频。MediaRecorder 作为状态机运行。

您需要设置不同的参数,比如源设备和格式。设置后,可执行任何时间长度的录制,直到用户停止。清单 2 包含的代码在 Android 设备上录制音频。显示的代码不包括应用程序的 UI 元素(完整源代码见 下载)。在 startRecording 方法中,实例化并初始化 MediaRecorder 的实例:

输入源被设置为麦克风(MIC)。输出格式被设置为 3GPP(*.3gp 文件),这是移动设备专用的媒体格式。编码器被设置为 AMR_NB,这是音频格式,采样率为 8 KHz。NB 表示窄频。SDK 文档 解释了不同的数据格式和可用的编码器。

音频文件存储在存储卡而不是内存中。External.getExternalStorageDirectory() 返回存储卡位置的名称,在该目录中将创建一个临时文件名。然后,通过调用 setOutputFile 方法将文件关联到 MediaRecorder 实例。音频数据将存储到该文件中。调用 prepare 方法完成 MediaRecorder 的初始化。

准备开始录制流程时,将调用 start 方法。在调用 stop 方法之前,将对存储卡上的文件进行录制。release 方法将释放分配给 MediaRecorder 实例的资源。在该代码样例中,processaudiofile 方法将音频添加到媒体库。使用 Intent 通知设备上的媒体应用程序有新内容可用。

关于该代码片段最后要注意的是:如果您试用,它一开始不会录制音频。您将看到创建的文件,但是没有任何音频。您需要向 AndroidManifest.xml 文件添加权限。现在,您已经学了一点关于与 Android 传感器和录制音频相关的内容。下一节将更全面的介绍与数据采集和报告系统有关的应用程序架构。

该架构很灵活;应用程序逻辑可以划分为本地 Android 设备和服务器端资源(可以实现更大的数据库和计算功能)。例如,本地 Android 设备上录制的音轨可以 POST 到 Web 服务器,其中将根据音频模式数据库比较数据。很明显,这仅仅是冰山一角。希望您能更深入地研究,让 Android 平台超越移动电话的范畴。

该架构很灵活;应用程序逻辑可以划分为本地 Android 设备和服务器端资源(可以实现更大的数据库和计算功能)。例如,本地 Android 设备上录制的音轨可以 POST 到 Web 服务器,其中将根据音频模式数据库比较数据。很明显,这仅仅是冰山一角。希望您能更深入地研究,让Android传感器超越移动电话的范畴。

Android 开发 — 传感器的值

  • 不同传感器的 listener 只能单独写出,尝试用一个 listener 监听所有传感器的变化失败。
  • 某个 listener 的监听速度设为 SENSOR_DELAY_FASTEST ,其他的也跟着变快。
  • 温度传感器变化很慢,有时候没有读数。

Java代码

1 package com.ldq.sensor.detail;

2

3 import android.app.Activity;

4 import android.hardware.Sensor;

5 import android.hardware.SensorEvent;

6 import android.hardware.SensorEventListener;

7 import android.hardware.SensorManager;

8 import android.os.Bundle;

9 import android.util.Log;

10 import android.widget.TextView;

11

12 public class ExSensorDetail extends Activity {

13

14     private TextView text1;

15     private TextView text2;

16     private TextView text3;

17     private TextView text4;

18     private TextView text5;

19     private TextView text6;

20     private TextView text7;

21     private TextView text8;

22     private TextView text9;

23     private TextView text10;

24

25     private SensorEventListener acc_listener = new SensorEventListener() {

26         @Override

27         public void onAccuracyChanged(Sensor sensor, int accuracy) {

28             // TODO Auto-generated method stub

29         }

30

31         @Override

32         public void onSensorChanged(SensorEvent event) {

33             // TODO Auto-generated method stub

34             Log.i("------", "" + "TYPE_ACCELEROMETER");

35             text1.setText("ACCELEROMETER_X: " + event.values[0]);

36             text2.setText("ACCELEROMETER_Y: " + event.values[1]);

37             text3.setText("ACCELEROMETER_Z: " + event.values[2]);

38         }

39     };

40

41     private SensorEventListener mag_listener = new SensorEventListener() {

42         @Override

43         public void onAccuracyChanged(Sensor sensor, int accuracy) {

44             // TODO Auto-generated method stub

45         }

46

47         @Override

48         public void onSensorChanged(SensorEvent event) {

49             // TODO Auto-generated method stub

50             text4.setText("MAGNETIC_FIELD_X: " + event.values[0]);

51             text5.setText("MAGNETIC_FIELD_Y: " + event.values[1]);

52             text6.setText("MAGNETIC_FIELD_Z: " + event.values[2]);

53         }

54     };

55

56     private SensorEventListener ori_listener = new SensorEventListener() {

57         @Override

58         public void onAccuracyChanged(Sensor sensor, int accuracy) {

59             // TODO Auto-generated method stub

60         }

61

62         @Override

63         public void onSensorChanged(SensorEvent event) {

64             // TODO Auto-generated method stub

65             text7.setText("ORIENTATION_X: " + event.values[0]);

66             text8.setText("ORIENTATION_Y: " + event.values[1]);

67             text9.setText("ORIENTATION_Z: " + event.values[2]);

68         }

69     };

70

71     private SensorEventListener tem_listener = new SensorEventListener() {

72         @Override

73         public void onAccuracyChanged(Sensor sensor, int accuracy) {

74             // TODO Auto-generated method stub

75         }

76

77         @Override

78         public void onSensorChanged(SensorEvent event) {

79             // TODO Auto-generated method stub

80             text10.setText("TEMPERATURE: " + event.values[0]);

81         }

82     };

83

84     /** Called when the activity is first created. */

85     @Override

86     public void onCreate(Bundle savedInstanceState) {

87         super.onCreate(savedInstanceState);

88         setContentView(R.layout.main);

89

90         text1 = (TextView) findViewById(R.id.TextView01);

91         text2 = (TextView) findViewById(R.id.TextView02);

92         text3 = (TextView) findViewById(R.id.TextView03);

93         text4 = (TextView) findViewById(R.id.TextView04);

94         text5 = (TextView) findViewById(R.id.TextView05);

95         text6 = (TextView) findViewById(R.id.TextView06);

96         text7 = (TextView) findViewById(R.id.TextView07);

97         text8 = (TextView) findViewById(R.id.TextView08);

98         text9 = (TextView) findViewById(R.id.TextView09);

99         text10 = (TextView) findViewById(R.id.TextView01);

100

101         SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

102         sm.registerListener(acc_listener, sm

103                 .getDefaultSensor(Sensor.TYPE_ACCELEROMETER),

104                 SensorManager.SENSOR_DELAY_NORMAL);

105         sm.registerListener(mag_listener, sm

106                 .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),

107                 SensorManager.SENSOR_DELAY_NORMAL);

108         sm.registerListener(ori_listener, sm

109                 .getDefaultSensor(Sensor.TYPE_ORIENTATION),

110                 SensorManager.SENSOR_DELAY_NORMAL);

111         sm.registerListener(tem_listener, sm

112                 .getDefaultSensor(Sensor.TYPE_TEMPERATURE),

113                 SensorManager.SENSOR_DELAY_NORMAL);

114

115     }

116 }

main.xml 文件

Java代码

117 <?xml version="1.0" encoding="utf-8"?>

118

119 <LinearLayout android:id="@+id/LinearLayout01"

120     android:layout_width="fill_parent" android:layout_height="fill_parent"

121     xmlns:android="http://schemas.android.com/apk/res/android"

122     android:orientation="vertical">

123     <TextView android:text="@+id/TextView01" android:id="@+id/TextView01"

124         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

125     <TextView android:text="@+id/TextView02" android:id="@+id/TextView02"

126         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

127     <TextView android:text="@+id/TextView03" android:id="@+id/TextView03"

128         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

129     <TextView android:text="@+id/TextView04" android:id="@+id/TextView04"

130         android:layout_width="wrap_content" android:layout_height="wrap_content"

131         android:layout_marginTop="10px"></TextView>

132     <TextView android:text="@+id/TextView05" android:id="@+id/TextView05"

133         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

134     <TextView android:text="@+id/TextView06" android:id="@+id/TextView06"

135         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

136     <TextView android:text="@+id/TextView07" android:id="@+id/TextView07"

137         android:layout_width="wrap_content" android:layout_height="wrap_content"

138         android:layout_marginTop="10px"></TextView>

139     <TextView android:text="@+id/TextView08" android:id="@+id/TextView08"

140         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

141     <TextView android:text="@+id/TextView09" android:id="@+id/TextView09"

142         android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>

143     <TextView android:text="@+id/TextView10" android:id="@+id/TextView10"

144         android:layout_width="wrap_content" android:layout_height="wrap_content"

145         android:layout_marginTop="10px"></TextView>

146 </LinearLayout>

Android 震动示例--心跳效果

正在开发第二个游戏,计时就要结束的时候,为了营造紧张的气氛,会利用手机自身的震动模拟心跳效果,其实这个心跳效果做起来真的非常的简单。所以直接上代码了(注意模拟器是模拟不了震动的,得真机测试哦):
程序效果:

Java代码

1 package com.ray.test;

2

3 import android.app.Activity;

4 import android.os.Bundle;

5 import android.os.Vibrator;

6 import android.view.MotionEvent;

7

8 public class TestViberation extends Activity {

9     Vibrator vibrator;

10     /** Called when the activity is first created. */

11     @Override

12     public void onCreate(Bundle savedInstanceState) {

13         super.onCreate(savedInstanceState);

14         setContentView(R.layout.main);

15     }

16

17     @Override

18     protected void onStop() {

19         if(null!=vibrator){

20             vibrator.cancel();

21         }

22         super.onStop();

23     }

24

25     @Override

26     public boolean onTouchEvent(MotionEvent event) {

27

28         if(event.getAction() == MotionEvent.ACTION_DOWN){

29              vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

30              long[] pattern = {800, 50, 400, 30}; // OFF/ON/OFF/ON...

31              vibrator.vibrate(pattern, 2);//-1不重复,非-1为从pattern的指定下标开始重复

32         }

33         return super.onTouchEvent(event);

34     }

35

36

37 }

Android重力感应Demo

android中的很多游戏的游戏都使用了重力感应的技术,但其api demo却并没有重力感应的实例(不知道是不是我没找到,找到的朋友麻烦告诉我一下,谢谢),因为开发的需要,就研究了一下重力感应这方面,因为网上关于这方面的东西比较少,所以写出来跟大家交流一下,算是抛砖引玉吧。(ps.因为重力感应式需要真机才能测试的,所以,下面提供的demo程序只能在真机上跑。)

因为官方说明比较含糊难懂,我用最简单的方式讲一下android重力感应系统的坐标系

http://dl.javaeye.com/upload/picture/pic/44045/8aff83b0-0a37-3870-979b-1b329569452d.jpg

以屏幕的左下方为原点(2d编程的时候,是以屏幕左上方为原点的,这个值得注意一下),箭头指向的方向为正。从-10到10,以浮点数为等级单位,想象一下以下情形:

手机屏幕向上(z轴朝天)水平放置的时侯,(x,y,z)的值分别为(0,0,10);

手机屏幕向下(z轴朝地)水平放置的时侯,(x,y,z)的值分别为(0,0,-10);

手机屏幕向左侧放(x轴朝天)的时候,(x,y,z)的值分别为(10,0,0);

手机竖直(y轴朝天)向上的时候,(x,y,z)的值分别为(0,10,0);

其他的如此类推,规律就是:朝天的就是正数,朝地的就是负数。利用x,y,z三个值求三角函数,就可以精确检测手机的运动状态了。

接下来,用最短的代码完成功能,程序效果就是在title上面输出x,y,z的值。

Java代码

1 package com.ray.test;

2 import android.app.Activity;

3 import android.os.Bundle;

4 import android.hardware.SensorManager;

5 import android.hardware.Sensor;

6 import android.hardware.SensorEventListener;

7 import android.hardware.SensorEvent;

8

9

10 ublic class SensorTest extends Activity {

11    private SensorManager sensorMgr;

12    Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

13    private float x, y, z;

14    protected void onCreate(Bundle savedInstanceState) {

15    super.onCreate(savedInstanceState);

16    sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

17        SensorEventListener lsn = new SensorEventListener() {

18            public void onSensorChanged(SensorEvent e) {

19              x = e.values[SensorManager.DATA_X];

20              y = e.values[SensorManager.DATA_Y];

21              z = e.values[SensorManager.DATA_Z];

22              setTitle("x="+(int)x+","+"y="+(int)y+","+"z="+(int)z);

23           }

24

25            public void onAccuracyChanged(Sensor s, int accuracy) {

26            }

27        };

28       //注册listener,第三个参数是检测的精确度

29        sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME);

30    }

31

32

 

关于手机重力感应的。

手机的感应器在Android里边所代表的类是Sensor,你只要看到在android.hardware这个包下边的都是封装的关于一些特殊的硬件方面的类,比如说Camera、Sensor之类的。

这里:Android重力感应Demo

代码很简单:我们首先要得到一个手机上的传感器。

Java代码

1 SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

这行代码只要用过类似开发的都应该知道是什么。

getSystemService(String name)可以用来返回一个硬件设备的控制器。比如说LocationManage(和GPS相关用来确定位置的)、 TelephonyManage(查询电话相关内容,比如说IMEI码)、AudioManager(顾名思义,是视频播放用的)等等。。。具体可以观看SDK文档里边 Activity的讲解。在线文档在这里(偶尔需要FQ)

得到重力感应的硬件控制了,然后我们就应该得到一个Sensor了。

Java代码

2 Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ALL);

关于这个参数。。。其实挺复杂的。。。。我开始用的是TYPE_ALL,出的是XYZ三条轴线的偏移量,至于其他的大家可以看下边:

下边是官方SDK中对于各种类型的解析(粗体红字是我加上去的)

<!-- =========== ENUM CONSTANT SUMMARY =========== -->

Constants

int

TYPE_ACCELEROMETER

A constant describing an accelerometer sensor type.加速度

int

TYPE_ALL

A constant describing all sensor types.所有类型,NexusOne默认为加速度

int

TYPE_GYROSCOPE

A constant describing a gyroscope sensor type回转仪

int

TYPE_LIGHT

A constant describing an light sensor type.光线感应吗

int

TYPE_MAGNETIC_FIELD

A constant describing a magnetic field sensor type.磁场

int

TYPE_ORIENTATION

A constant describing an orientation sensor type.定向(指北针)和角度

int

TYPE_PRESSURE

A constant describing a pressure sensor type压力计

int

TYPE_PROXIMITY

A constant describing an proximity sensor type.距离?

int

TYPE_TEMPERATURE

A constant describing a temperature sensor type温度啦

然后就是我们需要即时了解手机的偏转度。以TYPE_ALL为例子。(其实就是TYPE_ACCELEROMETER)

PS:有时候你的机子并不会拥有这么全的感应装置,这个时候你应该再进行以下判断。比如说:

Java代码

3 Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_TEMPERATURE);

4

5 if(sensor == null){

6         log.w("NO_SERVICE","没有感应温度的感应装置。")

7         ... ...

8 }else{

9         ... ...

10 }

所有最基本的三维坐标系有三个轴:X、Y和Z,这个学过矩阵或者线性代数的都应该知道吧。

关于手机的XYZ坐标,把你的手机平放到桌子上,横x,纵y,然后z就是屏幕法线。

官方的例子:(直接粘贴的话空格会变小,所以就截图了 )

然后我们注册一个Listener,用来监听我们所得到的值的改变。

Java代码

11 SensorEventListener lsn = new SensorEventListener() {

12             public void onSensorChanged(SensorEvent e) {

13                 x = e.values[SensorManager.DATA_X];

14                 y = e.values[SensorManager.DATA_Y];

15                 z = e.values[SensorManager.DATA_Z];

16                 t.setText("x=" + Math.round(x * ROUND_NUMBER) + "," + "y="

17                         + Math.round(y * ROUND_NUMBER) + "," + "z="

18                         + Math.round(z * ROUND_NUMBER));

19             }

20

21             public void onAccuracyChanged(Sensor s, int accuracy) {

22             }

23         };

在这里我把数字放大了,我预先定义了一个变量ROUND_NUMBER ,是为了以后用来更改灵敏度的。我取的值是100。

这个就简单了,我们首先声明一个SensorEvent的监听,每当它得到的值改变的时候,我就在一个TextView  t 上边输出改变了的值。

在这里使用TYPE_ALL返回的值SensorEvent里边的values就是得到的数字。

得到的values默认是一个float[]。也就是说是一个float类型的数组。他在TYPE_ALL的声明下一共返回三个值,分别就是x、y、z轴的值,假如你将手机平放在水平面上,默认分别是0,0,10。(我在网上查到有的人和我得到的数字不一样,有人说是0,0,-10,关于这个我不知道是为什么,如果有人的Gphone比较多的话可以看看是怎么一回事 ),而当你将手机垂直立起,显示的应当是0,10,0。

PS: SensorManager里边有很多的有意思的常量,比如说SensorManager.GRAVITY_EARTH 是地球的重力加速度,当然也有GRAVITY_MARS 火星的,GRAVITY_MOON 月球的,最恶搞的还有GRAVITY_DEATH_STAR_I (星球大战里的卫星武器死星I号)。。。。还有一个GRAVITY_THE_ISLAND ,这个不知道是哪里。。。汗。。。难道是《岛》这本书里的世界?还是Neverland?

然后我们可以给Manager注册一个监听。

Java代码

24 sensorMgr.registerListener(lsn, sensor,

25                 SensorManager.SENSOR_DELAY_GAME);

三个参数分别是监听,感应装置,和灵敏度。

灵敏度分为:

SENSOR_DELAY_FASTEST 最灵敏,快的然你无语
SENSOR_DELAY_GAME 游戏的时候用这个,不过一般用这个就够了,和上一个很难看出区别(也许是我的手机CPU高?1GHz的。。。)
SENSOR_DELAY_NORMAL 比较慢。
SENSOR_DELAY_UI最慢的,几乎就是横和纵的区别

也许有些人想要拿这个来练练手了。比如说是现在每天播放的联通iPhone广告里有一个“可以用来测量相框水平 ”这个广告词。

但是,但是。。。。恩恩。。。。输出的最好还是角度比较好吧?

所以我们改一改,做一个基本的LevelBar。。。没有什么图形界面,只是用来输出。

我们首先注册的Sensor应该改了。。。不是TYPE_ALL ,而是TYPE_ORIENTATION !

然后剩下的基本上都一样。SensorEvent 返回的values也是三个值的数组。但是,这三个值还是稍微有些不同的,如果你看了输出的值,那么就可能会明白了。

首先是第一个,有些人发现就算是平放在桌面上第一个值也会变,那么,第一个值其实不是轴角度,而是方向。

对了,这就是我在随上边写的指北针 !当数字是0 的时候,你的手机指向的是正北 方向,90的话是东 ,180是南 ,270是西 。这下子,再加上一个漂亮的图形界面,一个指南针软件就可以出来了吧。

然后是第二个和第三个,就是x,y轴的角度值!对,是角度值而且不用换算。这样子,你可以把屏幕横过来,然后直接输出y轴的角度值了,什么时候他是90度,那么就是水平了!(实例代发请参考google提供的指南针代码)

Android的传感器编程小结

这两天结合手机研究了下Android的传感器编程,现做一个小结:

(手机是G2 Magic,OS版本1.1)

传感器编程中,

1. Accelrator的x,y,z轴的正负向:
   手机屏幕向上水平放置时: (x,y,z) =  (0, 0, -10)  而不是 (0, 0, 10)
   当手机顶部抬起时: y减小,且为负值

当手机底部抬起时: y增加,且为正值

当手机右侧抬起时: x减小,且为负值

当手机左侧抬起时: x增加,且为正值

2.  Accelrator的z轴的变化:
       手机屏幕向上水平放置时,z= -10

手机屏幕竖直放置时,    z= 0

手机屏幕向下水平放置时,z= 10

3.  当x变为+5时, 手机画面切换为竖向
   
    当x变为-5时, 手机画面切换为横向

4.  传感器相关的类在SDK1.1和SDK1.5中不一样,因此实现代码也不一样

5. 传感器类型分为:方向、加速表、光线、磁场、临近性、温度等
    程序中分别为:
        方向:   SensorManager.SENSOR_ORIENTATION,   
        加速表: SensorManager.SENSOR_ACCELEROMETER
        光线:    SensorManager.SENSOR_LIGHT
        磁场:   SensorManager.SENSOR_MAGNETIC_FIELD
        临近性: SensorManager.SENSOR_PROXIMITY
        温度:   SensorManager.SENSOR_TEMPERATURE

采样率:最快、游戏、普通、用户界面。当应用程序请求特定的采样率时,其实只是对传感器子系统的一个提示

,或者一个建议。不保证特定的采样率可用。
        最快:     SensorManager.SENSOR_DELAY_FASTEST
        游戏:     SensorManager.SENSOR_DELAY_GAME
        普通:     SensorManager.SENSOR_DELAY_NORMAL
        用户界面: SensorManager.SENSOR_DELAY_UI

准确性: 高、低、中、不可靠。

6. Orientation Sensor三个坐标的含义:
   values[0]:方位角(水平旋转角),简单的说就是手机的头现在朝向哪个方位,0=北、90=东、180=南、270

=西(可是好像不太准)
   values[1]:纵向旋转角,0=面朝上平置、-90=垂直向上、-180/180=面朝下平置、90=垂直向下
   values[2]:橫向旋转角,0=朝前、90=往右倒、-90=往左倒

7. 自動偵測手機方向

要讓手機自動旋轉的話,只要在AndroidManifest.xml裡面把ORIENTAION改成sensor就好,可是要讓Activity偵測到

方向改變的話,要去抓Activity的Display:

if (getWindowManager().getDefaultDisplay().getOrientation() == 0) {
  //Do some portrait
} else {
  //Do some Landscape

要注意的是這裡的常數和ActivityInfo的不一樣,0是直的,1是橫的。

然後因為每次改變螢幕方向都會引發一連串的onPause, onDestory, onCreate,所以需要的處理全部寫在onCreate裡

面就大功告成。

参考资料:

1. 深入探讨 Android 传感器 
   http://www.ibm.com/developerworks/cn/opensource/os-android-sensor/index.html#download

2. Android应用开发实战:GPS与加速度传感器
   http://www.lupaworld.com/263077/viewspace-137400.html