Android特色開發(fā)之傳感器和語(yǔ)音識(shí)別分析
      
2011/02/11
隨著科技的快速演進(jìn),現(xiàn)代人對(duì)移動(dòng)通信、無(wú)線上網(wǎng)與多媒體娛樂的需求更甚以往,所謂的智能手機(jī)(Smart Phone)便成了炙手可熱的個(gè)人消費(fèi)電子產(chǎn)品之一,從Apple不斷推出iPhone企圖顛覆消費(fèi)者對(duì)手機(jī)的想象、RIM推出主打商務(wù)功能的黑莓機(jī)、Google的Android系統(tǒng)讓眾家手機(jī)廠商爭(zhēng)食大餅,到微軟屢敗屢戰(zhàn)的從WinMo一路開發(fā)到WP7,智能手機(jī)的這塊戰(zhàn)場(chǎng)可說(shuō)是打的如火如荼。然而在這些眾家競(jìng)爭(zhēng)者中,Android可說(shuō)是目前行情看俏的一套操作系統(tǒng),以國(guó)際市調(diào)研究機(jī)構(gòu)Gartner最新出爐2010年第三季的調(diào)查為例,采用Android操作系統(tǒng)的智能手機(jī)在過去一年以來(lái)成長(zhǎng)幅度最高,光是市占率便是前一年同期的七倍之多,銷售量更是達(dá)到14倍的成長(zhǎng),同時(shí)也一舉從市占率排名的第六名竄升到第二名。而在今年一月份甫落幕的國(guó)際消費(fèi)性電子展(CES),也處處可見各式各樣采用Android操作系統(tǒng)的產(chǎn)品。  下面我們通過一個(gè)例子來(lái)分析Android中傳感器的使用,這里分析的是方向傳感器(TYPE_ORIENTATION)。
        
          4.Android 中傳感器的功能
        
          要在Android中使用傳感器,首先需要了解SensorManager和SensorEventListener。顧名思義,SensorManager就是所有傳感器的一個(gè)綜合管理類,包括了傳感器的種類、采樣率、精準(zhǔn)度等。我們可以通過getSystemService方法來(lái)取得一個(gè)SensorManager對(duì)象。代碼如下:
        
          SensorManager mSensorManager = SensorManager)getSystemService(SENSOR_SERVICE);
        
          取得SensorManager對(duì)象之后,可以通過getSensorList方法來(lái)獲得我們需要的傳感器類型,保存到一個(gè)傳感器列表中。通過如下代碼可以得到一個(gè)方向傳感器:
        
          List sensors = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
        
          要與傳感器交互,應(yīng)用程序必須注冊(cè)以偵聽與一個(gè)或多個(gè)傳感器相關(guān)的活動(dòng)。Android中提供了registerListener來(lái)注冊(cè)一個(gè)傳感器,并提供了unregisterListener來(lái)卸載一個(gè)傳感器。registerListener方法包括3個(gè)參數(shù):第1個(gè)參數(shù),接收信號(hào)的Listener實(shí)例;第2個(gè)參數(shù),想接收的傳感器類型的列表(即上一步創(chuàng)建的List對(duì)象);第3個(gè)參數(shù),接收頻度。調(diào)用之后返回一個(gè)布爾值,true表示成功,false表示失敗。當(dāng)然,之后不再使用時(shí),我們還需要卸載。代碼如下:
        
          //注冊(cè)傳感器
          Boolean mRegisteredSensor = mSensorManager.registerListener(this, sensor, 
        SensorManager.SENSOR_DELAY_FASTEST);
          //卸載傳感器 
          mSensorManager.unregisterListener(this);
        
          其中,SensorEventListener是使用傳感器的核心部分,包括以下兩個(gè)方法必須實(shí)現(xiàn):
        
          onSensorChanged (SensorEvent event) 方法在傳感器值更改時(shí)調(diào)用。該方法只由受此應(yīng)用程序監(jiān)視的傳感器調(diào)用。該方法的參數(shù)包括一個(gè)SensorEvent對(duì)象,該對(duì)象主要包括一組浮點(diǎn)數(shù),表示傳感器獲得的方向、加速度等信息。例如,以下代碼可以取得其值:
        
          float x = event.values[SensorManager.DATA_X]; 
          float y = event.values[SensorManager.DATA_Y]; 
          float z = event.values[SensorManager.DATA_Z];
        
          onAccuracyChanged (Sensor sensor,int accuracy) 方法在傳感器的精準(zhǔn)度發(fā)生改變時(shí)調(diào)用。其參數(shù)包括兩個(gè)整數(shù):一個(gè)表示傳感器,另一個(gè)表示該傳感器新的準(zhǔn)確值。
        
          具體實(shí)現(xiàn)如代碼清單1所示。
        
          代碼清單1 \Examples_09_01\src\com\yarin\android\Examples_09_01\Activity01.java 
        
          public class Activity01 extends Activity implements SensorEventListener 
        
          {
          private boolean mRegisteredSensor; 
          //定義SensorManager
          private SensorManager mSensorManager; 
          public void onCreate(Bundle savedInstanceState) 
          { 
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main); 
          mRegisteredSensor = false; 
          //取得SensorManager實(shí)例 
          mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); 
          }
          protected void onResume()
          {
          super.onResume();
          //接收SensorManager的一個(gè)列表(Listener)
          //這里我們指定類型為TYPE_ORIENTATION(方向傳感器)
          List sensors = mSensorManager.getSensorList 
          (Sensor.TYPE_ORIENTATION); 
          if (sensors.size() > 0) 
          {
          Sensor sensor = sensors.get(0); 
          //注冊(cè)SensorManager 
          //this->接收sensor的實(shí)例 
          //接收傳感器類型的列表 
          //接收的頻率 
          mRegisteredSensor = mSensorManager.registerListener(this, 
          sensor, SensorManager.SENSOR_DELAY_FASTEST); 
          }
          } 
          protected void onPause() 
          {
          if (mRegisteredSensor) 
          { 
          //如果調(diào)用了registerListener 
          //這里我們需要unregisterListener來(lái)卸載/取消注冊(cè) 
          mSensorManager.unregisterListener(this); 
          mRegisteredSensor = false; 
          }
          super.onPause(); 
          }
          //當(dāng)精準(zhǔn)度發(fā)生改變時(shí) 
          //sensor->傳感器 
          //accuracy->精準(zhǔn)度 
          public void onAccuracyChanged(Sensor sensor, int accuracy) 
          { 
          //處理精準(zhǔn)度改變 
          }
          // 當(dāng)傳感器在被改變時(shí)觸發(fā) 
          public void onSensorChanged(SensorEvent event) 
          {
          // 接收方向傳感器的類型 
          if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) 
          { 
          //這里我們可以得到數(shù)據(jù),然后根據(jù)需要來(lái)處理 
          //由于模擬器上面無(wú)法測(cè)試效果,因此我們暫時(shí)不處理數(shù)據(jù) 
          float x = event.values[SensorManager.DATA_X]; 
          float y = event.values[SensorManager.DATA_Y]; 
          float z = event.values[SensorManager.DATA_Z]; 
          } 
          } 
          }
        
          上面的例子中演示了如何獲得方向傳感器的方向、加速度等信息,我們可以根據(jù)得到的數(shù)值與上一次得到的數(shù)值之間的關(guān)系來(lái)進(jìn)行需要的操作。SensorManager中還有很多常量和一些常用的方法,如下:
        
          getDefaultSensor:得到默認(rèn)的傳感器對(duì)象。
          getInclination:得到地磁傳感器傾斜角的弧度值。
          getOrientation:得到設(shè)備旋轉(zhuǎn)的方向。
          getSensorList:得到指定傳感器的列表。
        
        二、語(yǔ)音識(shí)別
        
          語(yǔ)音識(shí)別技術(shù)在手機(jī)上應(yīng)用得相當(dāng)廣泛,我們?nèi)粘W铑l繁的溝通方式是語(yǔ)音,在手機(jī)應(yīng)用中,大部分是通過硬件手動(dòng)輸入,目前這依然是主要與手機(jī)互動(dòng)的方式,然而對(duì)于像手機(jī)這種小巧的移動(dòng)設(shè)備來(lái)說(shuō),使用鍵盤甚至是虛擬鍵盤打字是一件非常不爽的事情。于是, 
        Google推出了強(qiáng)大的語(yǔ)音搜索業(yè)務(wù)。2008年11月,Google的語(yǔ)音搜索已經(jīng)在iPhone平臺(tái)上線,而Android在1.5 SDK版本中也加強(qiáng)了語(yǔ)音識(shí)別功能,并應(yīng)用到了搜索功能上,這的確是一個(gè)非常讓人驚喜的更新。我們只需要點(diǎn)擊搜索框旁邊的那個(gè)小話筒形狀的按鈕,如圖1所示,Android就可以通過語(yǔ)音識(shí)別你要搜索的內(nèi)容。如果你的語(yǔ)音不夠清晰,Android也可以通過大體的意思來(lái)提供一些選擇,其宗旨是最大限度地改善人機(jī)交互的便捷性。相信很快會(huì)有更多人性化的功能出現(xiàn)在Android平臺(tái)上,比如我們?cè)谕嬗螒驎r(shí),可以通過語(yǔ)音來(lái)控制操作,讓我們期待每一次革新帶給我們的便捷吧!
 
 
      
圖1:Android語(yǔ)音識(shí)別按鈕
   Android中主要通過RecognizerIntent來(lái)實(shí)現(xiàn)語(yǔ)音識(shí)別,它主要包括一些常量來(lái)表示語(yǔ)音的模式等,如表1所示。
        
          表1 RecognizerIntent包括的常量
 
 
      
   這里我們只需要通過Intent來(lái)傳遞一個(gè)動(dòng)作以及一些屬性,然后通過startActivityForResult來(lái)開始語(yǔ)音,代碼如下:
        
          Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 
        
          intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_
        
          MODEL_FREE_FORM);
        
          intent.putExtra(RecognizerIntent.EXTRA_PROMPT,"開始語(yǔ)音");
        
          startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
        
          當(dāng)然,如果找不到設(shè)置,就會(huì)拋出異常ActivityNotFoundException,所以我們需要捕捉這個(gè)異常。當(dāng)然,另外需要實(shí)現(xiàn)onActivityResult方法,當(dāng)語(yǔ)音結(jié)束時(shí),會(huì)觸發(fā)來(lái)獲得語(yǔ)音的字符序列。下面我們通過一個(gè)例子來(lái)學(xué)習(xí)語(yǔ)音識(shí)別,當(dāng)我們點(diǎn)擊“開始使用語(yǔ)音識(shí)別”按鈕時(shí),開始語(yǔ)音,然后在onActivityResult方法中取得結(jié)果并顯示出來(lái),運(yùn)行效果如圖2所示。由于在模擬器上沒有設(shè)備,所以顯示了ActivityNotFoundException異常,當(dāng)我們?cè)谡鏅C(jī)上測(cè)試、開始語(yǔ)音時(shí),如圖3所示,語(yǔ)音結(jié)束后取出的字符序列如圖所示。
 
 
      
圖:ActivityNotFoundException異常圖2開始語(yǔ)音圖3獲取的字符序列
   該例子很簡(jiǎn)單,具體實(shí)現(xiàn)如代碼清單所示。
        
          代碼清單
          \Examples_09_02\src\com\yarin\android\Examples_09_02\Activity01.java 
        
          public class Activity01 extends Activity 
          {
          private static final int VOICE_RECOGNITION_REQUEST_CODE = 4321;
          private ListView mList; 
          public void onCreate(Bundle savedInstanceState) 
          {
          super.onCreate(savedInstanceState); 
          setContentView(R.layout.main); 
          mList = (ListView) findViewById(R.id.ListView01); 
          Button button = (Button) findViewById(R.id.Button01); 
          button.setOnClickListener(new View.OnClickListener() 
          { 
          @Override 
          public void onClick(View v) 
          { 
          try 
          { 
          //通過Intent傳遞語(yǔ)音識(shí)別的模式,開啟語(yǔ)音 
          Intent intent = new Intent 
          (RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 
          //語(yǔ)言模式和自由形式的語(yǔ)音識(shí)別
          intent.putExtra(RecognizerIntent.EXTRA_ 
          LANGUAGE_MODEL,RecognizerIntent.
          LANGUAGE_MODEL_FREE_FORM); 
          //提示語(yǔ)音開始 
          intent.putExtra(RecognizerIntent.EXTRA_ 
          PROMPT,"開始語(yǔ)音");
          //開始執(zhí)行我們的Intent、語(yǔ)音識(shí)別 
          startActivityForResult(intent, 
          VOICE_RECOGNITION_REQUEST_CODE); 
          } 
          catch (ActivityNotFoundException e) 
          { 
          //找不到語(yǔ)音設(shè)備裝置 
          Toast.makeText(Activity01.this,
          "ActivityNotFoundException", 
          Toast.LENGTH_LONG).show(); 
          }
          } 
          }); 
          }
          //當(dāng)語(yǔ)音結(jié)束時(shí)的回調(diào)函數(shù)onActivityResult 
          @Override 
          protected void onActivityResult(int requestCode,int resultCode,Intent 
        data)
          { 
          // 判斷是否是我們執(zhí)行的語(yǔ)音識(shí)別 
          if(requestCode==VOICE_RECOGNITION_REQUEST_CODE&&resultCode==RESULT_OK)
          { 
          // 取得語(yǔ)音的字符 
          ArrayList<String> results = data.getStringArrayListExtra 
        
          RecognizerIntent.EXTRA_RESULTS); 
          //設(shè)置視圖更新 
          //mList.setAdapter(new ArrayAdapter<String>(this,android. 
        
          R.layout.simple_list_item_1,results)); 
          String resultsString = ""; 
          for (int i = 0; i < results.size(); i++) 
          { 
          resultsString += results.get(i);
          } 
          Toast.makeText(this,resultsString,Toast.LENGTH_LONG).show(); 
        
          super.onActivityResult(requestCode, resultCode, data); 
          } 
          } 
          }
        
OFweek電子工程網(wǎng)
| [英文]測(cè)試你的IVR-關(guān)鍵步驟 2011-01-26 | 
| 云計(jì)算占互聯(lián)網(wǎng)“高地” 多媒體應(yīng)用借機(jī)全面開花 2011-01-24 | 
| [英文]如何確保最大化關(guān)鍵任務(wù)IVR系統(tǒng)正常運(yùn)行時(shí)間 2010-12-10 | 
| 黑客攻擊新招:利用語(yǔ)音釣魚欺詐 2010-12-06 | 
| 我國(guó)號(hào)碼攜帶業(yè)務(wù)訪問數(shù)據(jù)庫(kù)技術(shù)方案的研究分析 2010-11-30 |