引言
由于为期半年的项目结束了,进入了一段“疗养”的真空期,因此有时间可以去归纳整理项目的经验,学习新的姿势与技巧,对自己技术水平也是一种提升。另外,个人懒癌症严重,为强迫自己努力学习,立了一些福来阁(比如没有写出博客女装什么的咳咳,我一定会拔旗成功的,哼),总体来说督促效果还是挺不错的。
项目中使用的Android和linux进行客户端的开发,结合项目的实战经验,七月份写的博客内容主要围绕Android开发进行,研究的内容预定为:Android中谷歌语音搜索功能探究(开篇),app应用意外关闭后MediaPlayer进行断点播放(预计两到三章左右)
为何选择Android谷歌语音搜索作为第一篇正式的博文?第一实现功能较为简单,代码量很小,可以为后续的文章热热身;第二语音搜索这个功能强大的,尤其是谷歌作为IT巨头,语音搜索体感非常棒,识别快而精准。谷歌的语音搜索可以广泛应用与基于LBS的Android应用程序中,调用谷歌api获取搜索结果,然后根据这个结果做自己想要的功能。
言归正传,下面开始正式介绍谷歌的语音搜索。
谷歌语音搜索基础
语音识别是Google在API Level3,也就是SDK1.5中引入的。根据官方的SDK的资料,语音检索的模式行为(action)有4种:
ACTION_GET_LANGUAGE_DETAILS ---> API Level8引入
ACTION_RECOGNIZE_SPEECH ---> API Level3引入
ACTION_VOICE_SEARCH_HANDS_FREE ---> API Level16引入
ACTION_WEB_SEARCH ---> API Level3引入
大致的功能为:
ACTION_GET_LANGUAGE_DETAILS:一个广播性质的intent,用于获取meta-data, 不常用。
ACTION_RECOGNIZE_SPEECH:起一个activity将用户所说的内容发送至语音识别器,结果将会从onActivityResult中返回。(注: 官方不再支持startActivity的方式起intent, 改为startActivityResult)。该部分是核心功能。
ACTION_VOICE_SEARCH_HANDS_FREE:API16中新引入的功能,不常用,目的是让用户在不使用客户端的情况下也能进行语音搜索,例如处于锁屏的安全模式中。如果要想使用该模式必须在manifest中加入如下:
1 <action android:name="android.speech.action.VOICE_SEARCH_HANDS_FREE" />
ACTION_WEB_SEARCH:通过Web网络检索来实现。
自定义设置项(Option)主要有以下3个:
EXTRA_LANGUAGE_MODEL:语音识别的语言设置
EXTRA_PROMPT: 语音输入时显示的提示文字
EXTRA_MAX_RESULTS: 语音搜索结果最大值设定
此外需要注意一点,在没有谷歌服务的地区是不能进行谷歌语音服务的,括弧笑。而且手机不支持语音搜索的话,本地需要预先安装一个语音包:Voice_Search_2.1.4.apk, 这个版本非常老,2011年出的一直没有更新,原生态的皮肤令人怀念。如果没有在google-market中下载到,可以到如下网址下载:
http://www.coolapk.com/apk/com.google.android.voicesearch
谷歌语音搜索的实现
实现的方法可以概括为以下四步:
1 起一个名为RecognizerIntent的Intent活动
2 putExtra中填入语音搜索的常量设定
3 startActivityResult
4 onActivityResult等待搜索结果。
核心代码示例:
添加一个RadiaGroup, 设置3种常用的语音搜索模式。
<RadioGroup android:id="@+id/search_group" android:orientation="vertical" android:layout_marginLeft="90dp" android:layout_width="wrap_content" android:layout_height="wrap_content"> <RadioButton android:checked="true" android:text="ACTION_RECOGNIZE_SPEECH" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioButton android:text="ACTION_WEB_SEARCH" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioButton android:text="ACTION_VOICE_SEARCH_HANDS_FREE" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RadioGroup>
在MainActivity中获取RadioGroup所选的内容,代码如下
1 private String getRecognizerMode() { 2 3 for (int i=0; i<radioBtn.getChildCount(); i++) { 4 5 RadioButton btn = (RadioButton) radioBtn.getChildAt(i); 6 7 if (btn.isChecked()) { 8 9 if (btn.getText().equals(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)) { 10 11 return RecognizerIntent.ACTION_RECOGNIZE_SPEECH; 12 13 } else if (btn.getText().equals(RecognizerIntent.ACTION_WEB_SEARCH)) { 14 15 return RecognizerIntent.ACTION_WEB_SEARCH; 16 17 } else if (btn.getText().equals(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE)) { 18 19 return RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE; 20 21 } 22 23 else { 24 25 return null; 26 27 } 28 29 } 30 31 } 32 33 return null; 34 35 }
然后是点击语音按钮后,执行startVoiceRecognition这个方法起intent操作
1 private void startVoiceRecognition(String mode) { 2 3 try { 4 5 Intent intent = new Intent(mode); 6 7 intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 8 9 RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 10 11 intent.putExtra(RecognizerIntent.EXTRA_PROMPT, R.string.voice_begin); 12 13 intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "zh-HK"); 14 15 startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE); 16 17 } catch (Exception e) { 18 19 e.printStackTrace(); 20 21 Toast.makeText(this, "No Google Voice app, plz download.", Toast.LENGTH_SHORT).show(); 22 23 } 24 25 }
在测试中发现,语音搜索所识别的内容依赖于机器的系统环境,如果是中文系统识别出的是中文的搜索内容,如果是日文系统的则是日文的搜索内容。RecognizerIntent.EXTRA_LANGUAGE这个属性似乎没有什么乱用。
最后是onActivityResult回调结果部分
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d("lsy", "onActivityResult --> requestCode: " + requestCode + " resultCode: " + resultCode); if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK) { ArrayList<String > results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); if (results.size() > 0) { String result = results.get(0).toString().trim(); if (null != result && result.length() > 0) { searchResult.setText(result); // 获取所有检索结果 // for (String str : results) { // searchResult.append(str + "/n"); // } } else { Toast.makeText(this, "Voice Content Fail", Toast.LENGTH_SHORT).show(); } } else { Log.d("lsy", "onActivityResult --> Voice Content Fail"); Toast.makeText(this, "Voice Content Fail", Toast.LENGTH_SHORT).show(); } } }
所有搜索的结果保存在一个ArrayList的列表中,第一个数据是匹配值最高,代码中因为需要拿最匹配的值去做地图搜索才会选择第一个数据。注释部分可以打印出所有满足搜索条件的值。
总结
谷歌的语音搜索可以帮助我们实现在LBS类应用中进行语音定位,其搜索精度高,速度快,只是不可描述的存在限制了这个好用的功能,很是可惜。后续基于谷歌语音开发的内容可以包括:历史语音搜索记录、语音联想功能、与自主开发导航软件的协同工作等,由于时间仓促没有来的及实现,有兴趣的朋友可以实验下。
本文对网上关于谷歌语音搜索的文章进行总结和部分拓展,做了点微小的贡献,甚是惭愧。
参考博文
http://blog.csdn.net/h7870181/article/details/11151773
http://blog.csdn.net/gumanren/article/details/6771265