引言
由於為期半年的項目結束了,進入了一段“療養”的真空期,因此有時間可以去歸納整理項目的經驗,學習新的姿勢與技巧,對自己技術水平也是一種提升。另外,個人懶癌症嚴重,為強迫自己努力學習,立了一些福來閣(比如沒有寫出博客女裝什么的咳咳,我一定會拔旗成功的,哼),總體來說督促效果還是挺不錯的。
項目中使用的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