应用程序(活动)暂停后,需要注销侦听器,这样以后就不会再收到传感器更新。这通过 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. 录制音频片段
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 平台超越移动电话的范畴。
结束语
在本文中,我们介绍了 Android 传感器。样例应用程序度量了方向和加速,以及使用 MediaRecorder 类与录制功能进行交互。对于构建实际系统,Android 是一个灵活、有吸引力的平台。Android 领域发展迅速,并且不断壮大。请务必关注该平台。(责任编辑:A6)