900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 深入探讨 Android 传感器

深入探讨 Android 传感器

时间:2019-06-02 21:27:44

相关推荐

深入探讨 Android 传感器

深入探讨 Android 传感器

随处监控您的环境

Android 是一个面向应用程序开发的富平台,它拥有许多具有吸引力的用户界面元素和数据管理功能。Android 还提供了一组丰富的接口选项。在本文中,学习如何配合使用 Android 的各种传感器选项监控您的环境。样例代码展示了如何在 Android 电话中录制音频。想构建自己的婴儿监视器吗?想用声音来接听电话或者打开房门吗?请学习如何利用配备有 Android 的设备的硬件功能。

简介

对于 Java 开发人员来说,Android 平台是通过使用硬件传感器创建创新应用程序的理想平台。我们将学习一些可用于 Android 应用程序的接口连接选项,包括使用传感器子系统和录制音频片段。

利用配备 Android 的设备的硬件功能可以构建哪些应用程序呢?任何需要电子监视和监听的应用程序都可以构建。婴儿监视器、安全系统,甚至地震仪都可以。理论上讲,您不能同时出现在两个地方,但 Android 可以利用一些可行的方法实现这一点。纵观本文始末,您必须记住,使用的 Android 设备不仅仅局限于 “手机”,还可以是部署在固定位置、具有无线网络连接的设备,比如 EDGE 或 WiFi。

Android 传感器功能

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

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

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

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

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 插件创建的应用程序。清单 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. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// get reference to SensorManagersm = (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);}@Overrideprotected void onResume() {super.onResume();// register this class as a listener for the orientation and accelerometer sensorssm.registerListener(this, SensorManager.SENSOR_ORIENTATION |SensorManager.SENSOR_ACCELEROMETER,SensorManager.SENSOR_DELAY_NORMAL);}@Overrideprotected void onStop() {// unregister listenersm.unregisterListener(this);super.onStop();} }

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

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

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

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

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

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

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

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

现在您已经了解了传感器子系统,接下来的部分将回顾一个在 Android 手机上录制音频的代码样例。该样例运行在 DEV1 开发设备上。

使用 MediaRecorder

android.media 包包含与媒体子系统交互的类。使用android.media.MediaRecorder类进行媒体采样,包括音频和视频。MediaRecorder作为状态机运行。您需要设置不同的参数,比如源设备和格式。设置后,可执行任何时间长度的录制,直到用户停止。

清单 2 包含的代码在 Android 设备上录制音频。显示的代码不包括应用程序的 UI 元素

清单 2. 录制音频片段

MediaRecorder mrec ;File audiofile = null;private static final String TAG="SoundRecordingDemo";protected void startRecording() throws IOException {mrec.setAudioSource(MediaRecorder.AudioSource.MIC);mrec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);if (mSampleFile == null) {File sampleDir = Environment.getExternalStorageDirectory();try { audiofile = File.createTempFile("ibm", ".3gp", sampleDir);}catch (IOException e) {Log.e(TAG,"sdcard access error");return;}}mrec.setOutputFile(audiofile.getAbsolutePath());mrec.prepare();mrec.start();}protected void stopRecording() {mrec.stop();mrec.release();processaudiofile(audiofile.getAbsolutePath());}protected void processaudiofile() {ContentValues values = new ContentValues(3);long current = System.currentTimeMillis();values.put(MediaStore.Audio.Media.TITLE, "audio" + audiofile.getName());values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/3gpp");values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());ContentResolver contentResolver = getContentResolver();Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;Uri newUri = contentResolver.insert(base, values);sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));}

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 文件添加权限:

<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>

现在,您已经学了一点关于与 Android 传感器和录制音频相关的内容。下一节将更全面的介绍与数据采集和报告系统有关的应用程序架构。

Android 作为传感器平台

Android 平台包含各种用于监视环境的传感器选项。有了输入或模拟选项数组,以及高级计算和互联功能,Android 成为构建实际系统的最佳平台。图 2 显示了输入、应用程序逻辑、通知方法或输出之间的简单视图。

图 2. 以 Android 为中心的传感器系统的方块图

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。