Android传感器编程入门
一、前言
我很喜欢电脑,可是笔记本还是太大,笔记本电脑再小还是要弄个小包背起来的,智能手机则不同,它完全就是一个手机,可以随意装在一个口袋里随身携带。因此我在2002年左右时最喜欢玩装备是Dell的PDA,2007年的时候最喜欢玩的是N73,而在2010年最喜欢玩的则是Milestone。眼见着手机的功能越来越强,时至今日智能手机甚至在某些方面已经强过了台式机和笔记本。本节课讲的就是智能手机强过台式机和笔记本的地方:传感器。
2008年的时候我很喜欢我的小白笔记本Macbook,喜欢玩它的一个小软件,一拍桌子,笔记本感受到了震动,它就转换了一个桌面出来,这让我像个小孩子一样没事就拍拍桌子。这一功能这得益于苹果笔记本内置有传感器。
我不知道iPhone手机是不是第一个把各种各样的传感器运用在手机上的,不过我知道iPhone是把传感器运用在手机上最成功的第一个。随后的Android系统也内置了大量的传感器,这让Android系统手机和普通的诺基亚智能机和Windows CE智能机相比牛气了许多,在拥有了Milestone之后,我的N73就被仍在抽屉的角落里了。
从Android1.5开始,系统内置了对多达八种传感器的支持,他们分别是:加速度传感器(accelerometer),陀螺仪(gyroscope),环境光照传感器(light),磁力传感器(magnetic field),方向传感器(orientation),压力传感器(pressure),距离传感器(proximity)和温度传感器(temperature)。
利用这些传感器我们可以制作出各种有趣的应用程序和游戏。譬如在口袋里晃一晃手机,手机就开始神不知鬼不觉的录音,不要着急这个很容易做,我们在本文的结尾就一起制作这个小应用。
本讲的学习方式还是在实战中学习,需要提醒的是模拟器中无法模拟传感器,因此你需要准备一款Android真机才能运行本讲的例子。
二、实例:手机传感器清单
我们还是先看程序后解释,
1、创建一个项目 Lesson37_HelloSensor , 主Activity名字叫 mainActivity.java
2、UI布局文件main.xml的内容如下:
1
|
<?xml version= "1.0" encoding= "utf-8" ?>
|
2
|
<linearlayout android:layout_height= "fill_parent" android:layout_width= "fill_parent" android:orientation= "vertical" xmlns:android= "/apk/res/android" >
|
3
|
<textview android:layout_height= "wrap_content" android:layout_width= "fill_parent" android:text= "" android:id= "@+id/TextView01" >
|
4
|
</textview></linearlayout>
|
3、mainActivity.java的内容如下:
01
|
package basic.android.lesson37;
|
02
|
03
|
import java.util.List;
|
04
|
05
|
import android.app.Activity;
|
06
|
import android.content.Context;
|
07
|
import android.hardware.Sensor;
|
08
|
import android.hardware.SensorManager;
|
09
|
import android.os.Bundle;
|
10
|
import android.widget.TextView;
|
11
|
12
|
public class MainActivity extends Activity {
|
13
|
14
|
/** Called when the activity is first created. */
|
15
|
@Override
|
16
|
public void onCreate(Bundle savedInstanceState) {
|
17
|
super .onCreate(savedInstanceState);
|
18
|
setContentView(R.layout.main);
|
19
|
20
|
//准备显示信息的UI组建
|
21
|
final TextView tx1 = (TextView) findViewById(R.id.TextView01);
|
22
|
23
|
//从系统服务中获得传感器管理器
|
24
|
SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
25
|
26
|
//从传感器管理器中获得全部的传感器列表
|
27
|
List<sensor> allSensors = sm.getSensorList(Sensor.TYPE_ALL);
|
28
|
29
|
//显示有多少个传感器
|
30
|
tx1.setText( "经检测该手机有" + allSensors.size() + "个传感器,他们分别是:\n" );
|
31
|
32
|
//显示每个传感器的具体信息
|
33
|
for (Sensor s : allSensors) {
|
34
|
35
|
String tempString = "\n" + " 设备名称:" + s.getName() + "\n" + " 设备版本:" + s.getVersion() + "\n" + " 供应商:"
|
36
|
+ s.getVendor() + "\n" ;
|
37
|
38
|
switch (s.getType()) {
|
39
|
case Sensor.TYPE_ACCELEROMETER:
|
40
|
tx1.setText(tx1.getText().toString() + s.getType() + " 加速度传感器accelerometer" + tempString);
|
41
|
break ;
|
42
|
case Sensor.TYPE_GYROSCOPE:
|
43
|
tx1.setText(tx1.getText().toString() + s.getType() + " 陀螺仪传感器gyroscope" + tempString);
|
44
|
break ;
|
45
|
case Sensor.TYPE_LIGHT:
|
46
|
tx1.setText(tx1.getText().toString() + s.getType() + " 环境光线传感器light" + tempString);
|
47
|
break ;
|
48
|
case Sensor.TYPE_MAGNETIC_FIELD:
|
49
|
tx1.setText(tx1.getText().toString() + s.getType() + " 电磁场传感器magnetic field" + tempString);
|
50
|
break ;
|
51
|
case Sensor.TYPE_ORIENTATION:
|
52
|
tx1.setText(tx1.getText().toString() + s.getType() + " 方向传感器orientation" + tempString);
|
53
|
break ;
|
54
|
case Sensor.TYPE_PRESSURE:
|
55
|
tx1.setText(tx1.getText().toString() + s.getType() + " 压力传感器pressure" + tempString);
|
56
|
break ;
|
57
|
case Sensor.TYPE_PROXIMITY:
|
58
|
tx1.setText(tx1.getText().toString() + s.getType() + " 距离传感器proximity" + tempString);
|
59
|
break ;
|
60
|
case Sensor.TYPE_TEMPERATURE:
|
61
|
tx1.setText(tx1.getText().toString() + s.getType() + " 温度传感器temperature" + tempString);
|
62
|
break ;
|
63
|
default :
|
64
|
tx1.setText(tx1.getText().toString() + s.getType() + " 未知传感器" + tempString);
|
65
|
break ;
|
66
|
}
|
67
|
}
|
68
|
69
|
}
|
70
|
}</sensor>
|
4、连接真机Milestone,编译并运行程序,显示结果如下:
5、结合上面的程序我们做一些解释。
- Android所有的传感器都归传感器管理器 SensorManager 管理,获取传感器管理器的方法很简单:
String service_name = Context.SENSOR_SERVICE;
SensorManager sensorManager = (SensorManager)getSystemService(service_name);
- 现阶段Android支持的传感器有8种,它们分别是:
传感器类型常量 内部整数值 中文名称 Sensor.TYPE_ACCELEROMETER 1 加速度传感器 Sensor.TYPE_MAGNETIC_FIELD 2 磁力传感器 Sensor.TYPE_ORIENTATION 3 方向传感器 Sensor.TYPE_GYROSCOPE 4 陀螺仪传感器 Sensor.TYPE_LIGHT 5 环境光照传感器 Sensor.TYPE_PRESSURE 6 压力传感器 Sensor.TYPE_TEMPERATURE 7 温度传感器 Sensor.TYPE_PROXIMITY 8 距离传感器 - 从传感器管理器中获取其中某个或者某些传感器的方法有如下三种:
第一种:获取某种传感器的默认传感器
Sensor defaultGyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
第二种:获取某种传感器的列表
List<Sensor> pressureSensors = sensorManager.getSensorList(Sensor.TYPE_PRESSURE);
第三种:获取所有传感器的列表,我们这个例子就用的第三种
List<Sensor> allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
- 对于某一个传感器,它的一些具体信息的获取方法可以见下表:
方法 描述 getMaximumRange() 最大取值范围 getName() 设备名称 getPower() 功率 getResolution() 精度 getType() 传感器类型 getVentor() 设备供应商 getVersion() 设备版本号
三、实例:窈窈录音器
通过上面的例子我们学会了如何获得某种类型的传感器,下面我通过一个实例来学会如何使用某一个类型的传感器。我们这里使用加速度传感器来实现这样一个功能:开启我们的录音程序放在你的口袋或者提包里,需要录音的时候把衣服整理一下,或者把提包挪动个位置,那么此时手机就会感受到变化从而开始录音。由此达到神不知鬼不觉的录音效果。说起来似乎有点神,其实做起来很简单,让我们开始吧。
简单的录音程序已经在第28讲的时候做过了,我们在28讲程序的基础上写本讲的代码。
1、新建一个项目 Lesson37_YYRecorder , 主文件叫 MainActivity.java ,具体信息都可以参见第二十八讲的“窈窈录音”的例子。
2、这里只贴出于28讲不同的 MainActivity.java 的代码,请注意看注释:
001
|
package basic.android.lesson37;
|
002
|
003
|
import java.io.File;
|
004
|
import java.io.IOException;
|
005
|
import java.util.Calendar;
|
006
|
import java.util.Locale;
|
007
|
008
|
import android.app.Activity;
|
009
|
import android.content.Context;
|
010
|
import android.hardware.Sensor;
|
011
|
import android.hardware.SensorEvent;
|
012
|
import android.hardware.SensorEventListener;
|
013
|
import android.hardware.SensorManager;
|
014
|
import android.media.MediaRecorder;
|
015
|
import android.os.Bundle;
|
016
|
import android.text.format.DateFormat;
|
017
|
import android.view.View;
|
018
|
import android.widget.Button;
|
019
|
import android.widget.TextView;
|
020
|
import android.widget.Toast;
|
021
|
022
|
public class MainActivity extends Activity {
|
023
|
024
|
//录音和停止按钮
|
025
|
private Button recordButton;
|
026
|
private Button stopButton;
|
027
|
028
|
//检测摇动相关变量
|
029
|
private long initTime = 0 ;
|
030
|
private long lastTime = 0 ;
|
031
|
private long curTime = 0 ;
|
032
|
private long duration = 0 ;
|
033
|
034
|
private float last_x = 0 .0f;
|
035
|
private float last_y = 0 .0f;
|
036
|
private float last_z = 0 .0f;
|
037
|
038
|
private float shake = 0 .0f;
|
039
|
private float totalShake = 0 .0f;
|
040
|
041
|
//媒体录音器对象
|
042
|
private MediaRecorder mr;
|
043
|
044
|
//是否正在录音
|
045
|
private boolean isRecoding = false ;
|
046
|
047
|
@Override
|
048
|
public void onCreate(Bundle savedInstanceState) {
|
049
|
super .onCreate(savedInstanceState);
|
050
|
setContentView(R.layout.main);
|
051
|
052
|
// UI组件
|
053
|
recordButton = (Button) this .findViewById(R.id.Button01);
|
054
|
stopButton = (Button) this .findViewById(R.id.Button02);
|
055
|
final TextView tx1 = (TextView) this .findViewById(R.id.TextView01);
|
056
|
057
|
// 录音按钮点击事件
|
058
|
recordButton.setOnClickListener( new View.OnClickListener() {
|
059
|
060
|
@Override
|
061
|
public void onClick(View v) {
|
062
|
//如果没有在录音,那么点击按钮可以开始录音
|
063
|
if (!isRecoding){
|
064
|
startRecord();
|
065
|
}
|
066
|
}
|
067
|
});
|
068
|
069
|
// 停止按钮点击事件
|
070
|
stopButton.setOnClickListener( new View.OnClickListener() {
|
071
|
072
|
@Override
|
073
|
public void onClick(View v) {
|
074
|
initShake();
|
075
|
//如果正在录音,那么可以停止录音
|
076
|
if (mr != null ) {
|
077
|
mr.stop();
|
078
|
mr.release();
|
079
|
mr = null ;
|
080
|
recordButton.setText( "录音" );
|
081
|
Toast.makeText(getApplicationContext(), "录音完毕" , Toast.LENGTH_LONG).show();
|
082
|
isRecoding = false ;
|
083
|
084
|
}
|
085
|
}
|
086
|
});
|
087
|
088
|
// 获取传感器管理器
|
089
|
SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
090
|
// 获取加速度传感器
|
091
|
Sensor acceleromererSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
092
|
093
|
// 定义传感器事件监听器
|
094
|
SensorEventListener acceleromererListener = new SensorEventListener() {
|
095
|
096
|
@Override
|
097
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
098
|
//什么也不干
|
099
|
}
|
100
|
101
|
//传感器数据变动事件
|
102
|
@Override
|
103
|
public void onSensorChanged(SensorEvent event) {
|
104
|
105
|
//如果没有开始录音的话可以监听是否有摇动事件,如果有摇动事件可以开始录音
|
106
|
if (!isRecoding){
|
107
|
//获取加速度传感器的三个参数
|
108
|
float x = event.values[SensorManager.DATA_X];
|
109
|
float y = event.values[SensorManager.DATA_Y];
|
110
|
float z = event.values[SensorManager.DATA_Z];
|
111
|
112
|
//获取当前时刻的毫秒数
|
113
|
curTime = System.currentTimeMillis();
|
114
|
115
|
//100毫秒检测一次
|
116
|
if ((curTime - lastTime) > 100 ) {
|
117
|
118
|
duration = (curTime - lastTime);
|
119
|
120
|
// 看是不是刚开始晃动
|
121
|
if (last_x == 0 .0f && last_y == 0 .0f && last_z == 0 .0f) {
|
122
|
//last_x、last_y、last_z同时为0时,表示刚刚开始记录
|
123
|
initTime = System.currentTimeMillis();
|
124
|
} else {
|
125
|
// 单次晃动幅度
|
126
|
shake = (Math.abs(x - last_x) + Math.abs(y - last_y) + Math.abs(z - last_z)) / duration * 100 ;
|
127
|
}
|
128
|
129
|
//把每次的晃动幅度相加,得到总体晃动幅度
|
130
|
totalShake += shake;
|
131
|
132
|
// 判断是否为摇动,这是我自己写的标准,不准确,只是用来做教学示例,别误会了^_^
|
133
|
if (totalShake > 10 && totalShake / (curTime - initTime) * 1000 > 10 ) {
|
134
|
startRecord();
|
135
|
initShake();
|
136
|
}
|
137
|
138
|
tx1.setText( "总体晃动幅度=" +totalShake+ "\n平均晃动幅度=" +totalShake / (curTime - initTime) * 1000 );
|
139
|
}
|
140
|
141
|
last_x = x;
|
142
|
last_y = y;
|
143
|
last_z = z;
|
144
|
lastTime = curTime;
|
145
|
}
|
146
|
}
|
147
|
148
|
};
|
149
|
150
|
//在传感器管理器中注册监听器
|
151
|
sm.registerListener(acceleromererListener, acceleromererSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
152
|
153
|
}
|
154
|
155
|
// 开始录音
|
156
|
public void startRecord() {
|
157
|
//把正在录音的标志设为真
|
158
|
isRecoding = true ;
|
159
|
//存放文件
|
160
|
File file = new File( "/sdcard/" + "YY"
|
161
|
+ new DateFormat().format( "yyyyMMdd_hhmmss" , Calendar.getInstance(Locale.CHINA)) + ".amr" );
|
162
|
163
|
Toast.makeText(getApplicationContext(), "正在录音,录音文件在" + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
|
164
|
165
|
// 创建录音对象
|
166
|
mr = new MediaRecorder();
|
167
|
168
|
// 从麦克风源进行录音
|
169
|
mr.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
|
170
|
171
|
// 设置输出格式
|
172
|
mr.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
|
173
|
174
|
// 设置编码格式
|
175
|
mr.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
|
176
|
177
|
// 设置输出文件
|
178
|
mr.setOutputFile(file.getAbsolutePath());
|
179
|
180
|
try {
|
181
|
// 创建文件
|
182
|
file.createNewFile();
|
183
|
// 准备录制
|
184
|
mr.prepare();
|
185
|
} catch (IllegalStateException e) {
|
186
|
e.printStackTrace();
|
187
|
} catch (IOException e) {
|
188
|
e.printStackTrace();
|
189
|
}
|
190
|
// 开始录制
|
191
|
mr.start();
|
192
|
recordButton.setText( "录音中……" );
|
193
|
}
|
194
|
195
|
//摇动初始化
|
196
|
public void initShake() {
|
197
|
lastTime = 0 ;
|
198
|
duration = 0 ;
|
199
|
curTime = 0 ;
|
200
|
initTime = 0 ;
|
201
|
last_x = 0 .0f;
|
202
|
last_y = 0 .0f;
|
203
|
last_z = 0 .0f;
|
204
|
shake = 0 .0f;
|
205
|
totalShake = 0 .0f;
|
206
|
}
|
207
|
}
|
3、连接真机Milestone,编译并运行程序:
晃动机器,开始录音
查看录音文件,效果还可以:
4、我们小结一下:
到Android2.2版本为止,系统并没有给开发者提供多少可用的包装好的传感器信息,只是提供了传感器发出的原始数据,这些原始数据存放在 event.values 的数组里,开发人员需要从这些裸数据总自行发掘有用的信息,譬如从加速度传感器的3维裸数据中获得摇动的判断(我的摇动判断很弱智,有时间再改吧……)。
好了本讲就先到这里,关于传感器有机会我们展开再谈,下次再见吧。
转载于:https://www.cnblogs.com/java-time/archive/2011/05/25/tt150.html
Android传感器编程入门相关推荐
- Android传感器编程入门(三)
上接<Android传感器编程入门(二)> 三.实例:窈窈录音器 通过上面的例子我们学会了如何获得某种类型的传感器,下面我通过一个实例来学会如何使用某一个类型的传感器.我们这里使用加速度传 ...
- 《Android游戏编程入门经典》——1.7节小结
本节书摘来自异步社区<Android游戏编程入门经典>一书中的第1章,第1.7节小结,作者[美]Jonathan S. Harbour,更多章节内容可以访问云栖社区"异步社区&q ...
- 免费分享:5本安卓开发经典书籍,Android 7编程入门经典(第4版),Android底层驱动分析和移植,底层驱动分析和移植
1.Android 7编程入门经典(第4版) 使用Android Studio 2 PDF 下载 下载地址: http://www.askwinds.com/r-c/down-info-02/579 ...
- 《Android游戏编程入门经典》——1.1节Android 4简介
本节书摘来自异步社区<Android游戏编程入门经典>一书中的第1章,第1.1节Android 4简介,作者[美]Jonathan S. Harbour,更多章节内容可以访问云栖社区&qu ...
- Android 4编程入门经典 开发智能手机与平板电脑
查看书籍详细信息: Android 4编程入门经典--开发智能手机与平板电脑-- 编辑推荐 Wei-Meng Lee 最新作品,国内首本译著android 4入门宝典 内容简介 Android 4的问 ...
- Android 4编程入门经典—开发智能手机与平板电脑应用
Android 4编程入门经典 书名: Android 4编程入门经典 原书名: Beginning Android 4 Application Development 重点指数 畅销书 作者: ( ...
- 安卓android studio传感器编程入门demo读懂就通1分钟跑通掌握最多需要三十分钟
xml部分 自写的文件读取.存储.写入字符串 的类FileUtils.java MainActivity文件 附:完整代码(如果看上图不能解决问题的话,可以看看) Android获取手机传感器数据 ...
- Android传感器编程带实例
一.前言 我很喜欢电脑,可是笔记本还是太大,笔记本电脑再小还是要弄个小包背起来的,智能手机则不同,它完全就是一个手机,可以随意装在一个口袋里随身携带.因此我在2002年左右时最喜欢玩装备是Dell的P ...
- Android网络编程入门解析
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
最新文章
- jstack 脚本 自动日志_用jstack自动化捕抓异常java代码脚本
- String内存分配
- 不是有效的win32应用程序_杀毒软件有坑!三分之二的安卓杀毒软件的“主业”并不是杀毒...
- 配置过程中的一些问题
- kafka内置分区及自定义分区
- 大数据究竟是什么?一句话让你认识并读懂大数据
- 超详细 excel 基础知识
- matlab批量修改指定像素
- Scala中的fold和reduce理解
- 魔百盒CM311-1_S905L3芯片_YST代工_红外蓝牙语音_安卓9.0_线刷固件包
- Thread线程中的stop方法过时问题
- SQL(Oracle) 日期转换为英文年月格式
- 春天来了,该播种了。久久荒芜的博客重新耕种起来
- arduino环境esp32跑freertos系统实现触摸检测及wifi控制
- arcsde mysql_ArcSDE空间数据库安装配置问题
- 3、Spring Bean生命周期
- 官方MySQL解压版安装说明
- python图片马赛克_python检测图片是否有马赛克内容
- 威堡智慧酒店IPTV解决方案功能介绍
- 机械设计基础B【3】凸轮
热门文章
- 大学每天打游戏,不是混吃等死是什么?
- [图神经网络] 图节点Node表示---GCN
- [Golang] GOROOT、GOPATH和Project目录说明
- Perl获取当前系统时间
- Eigen入门之密集矩阵 3 - Array操作
- 用camelot读取表格_如何使用Camelot从PDF提取表格
- 扫描二维码读取文档_使用深度学习读取和分类扫描的文档
- 利用colab保存模型_在Google Colab上训练您的机器学习模型中的“后门”
- “80后”作家应扮演更重要的角色
- 底部检测的do...while循环