Android特色開發(fā)之傳感器和語音識(shí)別分析
2011/02/11
隨著科技的快速演進(jìn),現(xiàn)代人對(duì)移動(dòng)通信、無線上網(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àn)的從WinMo一路開發(fā)到WP7,智能手機(jī)的這塊戰(zhàn)場(chǎng)可說是打的如火如荼。然而在這些眾家競爭者中,Android可說是目前行情看俏的一套操作系統(tǒng),以國際市調(diào)研究機(jī)構(gòu)Gartner最新出爐2010年第三季的調(diào)查為例,采用Android操作系統(tǒng)的智能手機(jī)在過去一年以來成長幅度最高,光是市占率便是前一年同期的七倍之多,銷售量更是達(dá)到14倍的成長,同時(shí)也一舉從市占率排名的第六名竄升到第二名。而在今年一月份甫落幕的國際消費(fèi)性電子展(CES),也處處可見各式各樣采用Android操作系統(tǒng)的產(chǎn)品。 下面我們通過一個(gè)例子來分析Android中傳感器的使用,這里分析的是方向傳感器(TYPE_ORIENTATION)。
4.Android 中傳感器的功能
要在Android中使用傳感器,首先需要了解SensorManager和SensorEventListener。顧名思義,SensorManager就是所有傳感器的一個(gè)綜合管理類,包括了傳感器的種類、采樣率、精準(zhǔn)度等。我們可以通過getSystemService方法來取得一個(gè)SensorManager對(duì)象。代碼如下:
SensorManager mSensorManager = SensorManager)getSystemService(SENSOR_SERVICE);
取得SensorManager對(duì)象之后,可以通過getSensorList方法來獲得我們需要的傳感器類型,保存到一個(gè)傳感器列表中。通過如下代碼可以得到一個(gè)方向傳感器:
List sensors = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
要與傳感器交互,應(yīng)用程序必須注冊(cè)以偵聽與一個(gè)或多個(gè)傳感器相關(guān)的活動(dòng)。Android中提供了registerListener來注冊(cè)一個(gè)傳感器,并提供了unregisterListener來卸載一個(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來卸載/取消注冊(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ù)需要來處理
//由于模擬器上面無法測(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)系來進(jìn)行需要的操作。SensorManager中還有很多常量和一些常用的方法,如下:
getDefaultSensor:得到默認(rèn)的傳感器對(duì)象。
getInclination:得到地磁傳感器傾斜角的弧度值。
getOrientation:得到設(shè)備旋轉(zhuǎn)的方向。
getSensorList:得到指定傳感器的列表。
二、語音識(shí)別
語音識(shí)別技術(shù)在手機(jī)上應(yīng)用得相當(dāng)廣泛,我們?nèi)粘W铑l繁的溝通方式是語音,在手機(jī)應(yīng)用中,大部分是通過硬件手動(dòng)輸入,目前這依然是主要與手機(jī)互動(dòng)的方式,然而對(duì)于像手機(jī)這種小巧的移動(dòng)設(shè)備來說,使用鍵盤甚至是虛擬鍵盤打字是一件非常不爽的事情。于是,
Google推出了強(qiáng)大的語音搜索業(yè)務(wù)。2008年11月,Google的語音搜索已經(jīng)在iPhone平臺(tái)上線,而Android在1.5 SDK版本中也加強(qiáng)了語音識(shí)別功能,并應(yīng)用到了搜索功能上,這的確是一個(gè)非常讓人驚喜的更新。我們只需要點(diǎn)擊搜索框旁邊的那個(gè)小話筒形狀的按鈕,如圖1所示,Android就可以通過語音識(shí)別你要搜索的內(nèi)容。如果你的語音不夠清晰,Android也可以通過大體的意思來提供一些選擇,其宗旨是最大限度地改善人機(jī)交互的便捷性。相信很快會(huì)有更多人性化的功能出現(xiàn)在Android平臺(tái)上,比如我們?cè)谕嬗螒驎r(shí),可以通過語音來控制操作,讓我們期待每一次革新帶給我們的便捷吧!
圖1:Android語音識(shí)別按鈕
Android中主要通過RecognizerIntent來實(shí)現(xiàn)語音識(shí)別,它主要包括一些常量來表示語音的模式等,如表1所示。
表1 RecognizerIntent包括的常量
這里我們只需要通過Intent來傳遞一個(gè)動(dòng)作以及一些屬性,然后通過startActivityForResult來開始語音,代碼如下:
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_
MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,"開始語音");
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
當(dāng)然,如果找不到設(shè)置,就會(huì)拋出異常ActivityNotFoundException,所以我們需要捕捉這個(gè)異常。當(dāng)然,另外需要實(shí)現(xiàn)onActivityResult方法,當(dāng)語音結(jié)束時(shí),會(huì)觸發(fā)來獲得語音的字符序列。下面我們通過一個(gè)例子來學(xué)習(xí)語音識(shí)別,當(dāng)我們點(diǎn)擊“開始使用語音識(shí)別”按鈕時(shí),開始語音,然后在onActivityResult方法中取得結(jié)果并顯示出來,運(yùn)行效果如圖2所示。由于在模擬器上沒有設(shè)備,所以顯示了ActivityNotFoundException異常,當(dāng)我們?cè)谡鏅C(jī)上測(cè)試、開始語音時(shí),如圖3所示,語音結(jié)束后取出的字符序列如圖所示。
圖:ActivityNotFoundException異常圖2開始語音圖3獲取的字符序列
該例子很簡單,具體實(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傳遞語音識(shí)別的模式,開啟語音
Intent intent = new Intent
(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
//語言模式和自由形式的語音識(shí)別
intent.putExtra(RecognizerIntent.EXTRA_
LANGUAGE_MODEL,RecognizerIntent.
LANGUAGE_MODEL_FREE_FORM);
//提示語音開始
intent.putExtra(RecognizerIntent.EXTRA_
PROMPT,"開始語音");
//開始執(zhí)行我們的Intent、語音識(shí)別
startActivityForResult(intent,
VOICE_RECOGNITION_REQUEST_CODE);
}
catch (ActivityNotFoundException e)
{
//找不到語音設(shè)備裝置
Toast.makeText(Activity01.this,
"ActivityNotFoundException",
Toast.LENGTH_LONG).show();
}
}
});
}
//當(dāng)語音結(jié)束時(shí)的回調(diào)函數(shù)onActivityResult
@Override
protected void onActivityResult(int requestCode,int resultCode,Intent
data)
{
// 判斷是否是我們執(zhí)行的語音識(shí)別
if(requestCode==VOICE_RECOGNITION_REQUEST_CODE&&resultCode==RESULT_OK)
{
// 取得語音的字符
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 |
黑客攻擊新招:利用語音釣魚欺詐 2010-12-06 |
我國號(hào)碼攜帶業(yè)務(wù)訪問數(shù)據(jù)庫技術(shù)方案的研究分析 2010-11-30 |