`

深入探讨 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.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 展示了该应用程序的运行情况。


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

  1. view plaincopy to clipboardprint?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();       }       }  package com.msi.ibm.eyes;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.util.Log;
  5. import android.widget.TextView;
  6. import android.hardware.SensorManager;
  7. import android.hardware.SensorListener;
  8. public class IBMEyes extends Activity implements SensorListener {
  9.     final String tag = "IBMEyes";
  10.     SensorManager sm = null;
  11.     TextView xViewA = null;
  12.     TextView yViewA = null;
  13.     TextView zViewA = null;
  14.     TextView xViewO = null;
  15.     TextView yViewO = null;
  16.     TextView zViewO = null;

  17.     /** Called when the activity is first created. */
  18.     @Override
  19.     public void onCreate(Bundle savedInstanceState) {
  20.         super.onCreate(savedInstanceState);
  21.        // get reference to SensorManager
  22.         sm = (SensorManager) getSystemService(SENSOR_SERVICE);
  23.         setContentView(R.layout.main);
  24.         xViewA = (TextView) findViewById(R.id.xbox);
  25.         yViewA = (TextView) findViewById(R.id.ybox);
  26.         zViewA = (TextView) findViewById(R.id.zbox);
  27.         xViewO = (TextView) findViewById(R.id.xboxo);
  28.         yViewO = (TextView) findViewById(R.id.yboxo);
  29.         zViewO = (TextView) findViewById(R.id.zboxo);
  30.     }
  31.     public void onSensorChanged(int sensor, float[] values) {
  32.         synchronized (this) {
  33.             Log.d(tag, "onSensorChanged: " + sensor + ", x: " +
  34. values[0] + ", y: " + values[1] + ", z: " + values[2]);
  35.             if (sensor == SensorManager.SENSOR_ORIENTATION) {
  36.                 xViewO.setText("Orientation X: " + values[0]);
  37.                 yViewO.setText("Orientation Y: " + values[1]);
  38.                 zViewO.setText("Orientation Z: " + values[2]);
  39.             }
  40.             if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
  41.                 xViewA.setText("Accel X: " + values[0]);
  42.                 yViewA.setText("Accel Y: " + values[1]);
  43.                 zViewA.setText("Accel Z: " + values[2]);
  44.             }            
  45.         }
  46.     }
  47.    
  48.     public void onAccuracyChanged(int sensor, int accuracy) {
  49.             Log.d(tag,"onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);
  50.     }
  51.     @Override
  52.     protected void onResume() {
  53.         super.onResume();
  54.       // register this class as a listener for the orientation and accelerometer sensors
  55.         sm.registerListener(this,
  56.                 SensorManager.SENSOR_ORIENTATION |SensorManager.SENSOR_ACCELEROMETER,
  57.                 SensorManager.SENSOR_DELAY_NORMAL);
  58.     }
  59.    
  60.     @Override
  61.     protected void onStop() {
  62.         // unregister listener
  63.         sm.unregisterListener(this);
  64.         super.onStop();
  65.     }   
  66. }
复制代码

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

该活动的 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 手机上录制音频的代码样例。该样例运行在 DEV1 开发设备上。

使用 MediaRecorder

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

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

清单 2. 录制音频片段

  1. view plaincopy to clipboardprint?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));   }  MediaRecorder mrec ;
  2. File audiofile = null;
  3. private static final String TAG="SoundRecordingDemo";
  4. protected void startRecording() throws IOException
  5. {
  6.    mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
  7.    mrec.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  8.    mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  9.    if (mSampleFile == null)
  10.    {
  11.        File sampleDir = Environment.getExternalStorageDirectory();
  12.        try
  13.        {
  14.           audiofile = File.createTempFile("ibm", ".3gp", sampleDir);
  15.        }
  16.        catch (IOException e)
  17.        {
  18.            Log.e(TAG,"sdcard access error");
  19.            return;
  20.        }
  21.    }
  22.    mrec.setOutputFile(audiofile.getAbsolutePath());
  23.    mrec.prepare();
  24.    mrec.start();
  25. }
  26. protected void stopRecording()
  27. {
  28.    mrec.stop();
  29.    mrec.release();
  30.    processaudiofile(audiofile.getAbsolutePath());
  31. }
  32. protected void processaudiofile()
  33. {
  34.    ContentValues values = new ContentValues(3);
  35.    long current = System.currentTimeMillis();
  36.    values.put(MediaStore.Audio.Media.TITLE, "audio" + audiofile.getName());
  37.    values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
  38.    values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/3gpp");
  39.    values.put(MediaStore.Audio.Media.DATA, audiofile.getAbsolutePath());
  40.    ContentResolver contentResolver = getContentResolver();
  41.    
  42.    Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  43.    Uri newUri = contentResolver.insert(base, values);
  44.    
  45.    sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
  46. }
复制代码

在 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 显示了输入、应用程序逻辑、通知方法或输出之间的简单视图。

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

结束语

在本文中,我们介绍了 Android 传感器。样例应用程序度量了方向和加速,以及使用 MediaRecorder 类与录制功能进行交互。对于构建实际系统,Android 是一个灵活、有吸引力的平台。Android 领域发展迅速,并且不断壮大。

分享到:
评论

相关推荐

    深入探讨 Android 传感器(源代码及文档)

    我们介绍了 Android 传感器。样例应用程序度量了方向和加速,以及使用 MediaRecorder 类与录制功能进行交互。对于构建实际系统,Android 是一个灵活、有吸引力的平台。Android 领域发展迅速,并且不断壮大。请务必...

    Android传感器的分析

    本篇将深入探讨Android传感器的分析,包括如何获取传感器数据、解析数据以及常见的传感器类型。 一、Android传感器框架 Android提供了一个强大的传感器框架,它允许开发者访问设备上的各种传感器,通过`...

    详解Android 传感器开发 完全解析

    本文将深入探讨Android传感器的三大类别、Android传感器框架及其关键组件,为开发者提供全面的指南。 首先,我们来了解Android中的三大类传感器: 1. 动作传感器:这一类传感器主要用于检测设备在空间中的运动和...

    Android 传感器 Sensor 编程

    本章节将深入探讨Android传感器编程的相关知识点。 #### 二、Android传感器的基础概念 Android SDK 提供了一系列与硬件交互的功能,其中包括传感器管理。这些功能使得开发者能够创建出更加智能和响应式的应用。...

    android传感器检测源代码

    下面,我们将深入探讨Android传感器的工作原理和相关开发过程。 1. **Android传感器框架** Android系统提供了一个完善的传感器框架,使得开发者可以方便地访问和管理设备上的各种传感器。这个框架包括`...

    android 传感器测试

    本文将深入探讨Android传感器的测试,以帮助开发者更好地理解和运用这些传感器。 首先,我们来看看“传感器配置”。在Android系统中,传感器是由Android硬件抽象层(HAL)管理的,它们通过SensorService向应用程序...

    android的传感器系统

    在深入探讨Android传感器系统之前,我们首先要了解传感器在智能手机中的作用。传感器系统可以使智能手机的功能变得更加丰富多彩,而在Android系统中,这一系统支持多种传感器。这些传感器已经内置在Android框架中,...

    Android传感器高级编程

    《Android传感器高级编程》是专为开发者深入理解并掌握Android平台上的传感器技术而编写的一本专业书籍。在Android系统中,传感器是设备与环境交互的关键组件,它们收集各种物理和环境数据,如加速度、陀螺仪、磁力...

    Android传感器系列介绍-Oak先生

    本文将深入探讨Android传感器,特别是加速度传感器,并简要提及动作、位置和环境传感器的使用。 首先,加速度传感器是Android设备中最常见的传感器之一,它能够检测设备在三维空间中的线性加速度。这包括由于重力...

    Android 重力传感器源码.zip

    为了理解这些源码,我们需要深入探讨Android传感器框架以及重力传感器的工作原理。 Android系统的传感器架构基于硬件抽象层(HAL)和传感器服务(Sensor Service)。HAL为上层软件提供了一个统一的接口,使得系统...

    android 传感器

    本篇将深入探讨Android传感器的相关知识,包括传感器的基本概念、类型、API使用以及示例应用。 一、传感器基本概念 1. 传感器(Sensor):是硬件设备,它能够感知环境变化并将其转换为可读信号。Android系统通过...

    Android_传感器_API

    本文将深入探讨Android传感器API的相关概念、类和接口,以及如何使用它们来创建应用程序。 首先,让我们理解传感器的基本概念。传感器是一种能够感知物理现象,如温度、加速度等,并将其转化为可读电子信号的设备。...

    android平台传感器,指南针程序源码

    本文将深入探讨Android传感器系统,指南针程序的实现原理,并提供相关源码分析。 首先,Android系统提供了丰富的传感器接口,通过SensorManager服务来访问。SensorManager能够获取到设备上的所有传感器,包括加速度...

    Android的传感器系统1

    本篇文章将深入探讨Android传感器系统的主要方面,包括系统综述、层次结构、硬件抽象层以及传感器的使用。 首先,传感器系统综述强调了Android系统对多种传感器的支持,这些传感器类型包括加速度计(SENSOR_TYPE_...

    Android传感器高级编程 中文版 带书签 PDF

    《Android传感器高级编程》这本书是针对Android平台的传感器技术进行深入探讨的专业著作,旨在帮助开发者理解和利用Android系统中的传感器功能,提升应用的创新性和实用性。这本书由清华大学出版社出版,共481页,...

    Android传感器应用之摇一摇小球运动实现

    本篇文章将深入探讨如何在Android中实现摇一摇小球运动的效果。 首先,我们需要理解Android的传感器系统。Android提供了SensorManager类来管理和处理设备上的各种传感器数据,如加速度计。加速度计是实现摇一摇功能...

Global site tag (gtag.js) - Google Analytics