本章將創(chuàng)建一款“開車不發(fā)短信”的應(yīng)用,讓你在開車時(shí)能夠自動(dòng)回復(fù)收到的短信。一名計(jì)算機(jī)入門課上的新生首創(chuàng)了這款應(yīng)用,與美國(guó)國(guó)家農(nóng)場(chǎng)保險(xiǎn)公司開發(fā)的一款裝機(jī)量巨大的應(yīng)用相類似。App Inventor可以利用Android手機(jī)中的某些強(qiáng)大功能,包括SMS短信處理、數(shù)據(jù)庫(kù)管理、文本轉(zhuǎn)成語(yǔ)音以及位置傳感器等,本應(yīng)用就是一個(gè)典型的例子。
美國(guó)國(guó)家安全委員會(huì)(NSC)于2010年1月發(fā)布的研究結(jié)果表明,每年有至少28%的交通事故——將近160萬(wàn)次車禍源于司機(jī)在開車時(shí)使用手機(jī),其中至少20萬(wàn)次交通事故與發(fā)短信有關(guān)(http://www.nsc.org/pages/nscestimates16millioncrashescausedbydriversusingcellphonesandtexting.aspx)。因此,許多國(guó)家已經(jīng)全面禁止司機(jī)開車時(shí)使用手機(jī)。
Daniel Finnegan,一個(gè)舊金山大學(xué)的學(xué)生,在2010年秋季學(xué)期的App Inventor編程課上,提出了一個(gè)了不起的想法,用一個(gè)應(yīng)用來(lái)解決開車發(fā)短信泛濫的問題。如圖4-1所示,他創(chuàng)建的應(yīng)用可以對(duì)收到的任何短信進(jìn)行自動(dòng)回復(fù),如回復(fù)“我正在開車,稍后與您聯(lián)系”之類的內(nèi)容。
圖 4-1 “開車不發(fā)短信”
課堂上的頭腦風(fēng)暴增加了應(yīng)用的功能,也豐富了本教程,這些內(nèi)容發(fā)布在App Inventor網(wǎng)站上:
用戶可以根據(jù)情況改變回復(fù)內(nèi)容:例如,如果你正在開會(huì)或看電影,而不是開車,回復(fù)內(nèi)容可以做相應(yīng)的修改;
應(yīng)用可以大聲朗讀來(lái)信內(nèi)容:盡管有自動(dòng)回復(fù),但對(duì)來(lái)信的好奇心也會(huì)置你于死地;
就在本應(yīng)用發(fā)布到App Inventor網(wǎng)站后的幾周,State Farm Insurance創(chuàng)建了名為“On the Move”的Android應(yīng)用,http://www.statefarm.com/aboutus/newsroom/20100819.asp【譯者沒找到On the Move,不過該公司的確有幾個(gè)好的應(yīng)用值得嘗試】,其功能與“開車不發(fā)短信”類似。該公司將這項(xiàng)服務(wù)作為“掌上代理”應(yīng)用的升級(jí)內(nèi)容,免費(fèi)向所有人開放,并在YouTube網(wǎng)站發(fā)布視頻:http://www.youtube.com/watch?v=3xtjzO0-Hfw【譯者訪問該網(wǎng)址,提示“此視頻未公開”】。
我們無(wú)法確認(rèn)Daniel的應(yīng)用或App Inventor網(wǎng)站的教程是否對(duì)“On the Move”產(chǎn)生了影響,但有趣的是,這讓我們思考一種可能性:在一門編程基礎(chǔ)課上創(chuàng)建的應(yīng)用(竟然由一個(gè)創(chuàng)意寫作的學(xué)生創(chuàng)建!)也許會(huì)促成軟件的批量生產(chǎn),或至少是對(duì)軟件生產(chǎn)的生態(tài)系統(tǒng)有所貢獻(xiàn)。當(dāng)然,這也說(shuō)明了App Inventor降低了軟件開發(fā)的門檻,以至于無(wú)論是誰(shuí),只要有一個(gè)好主意,都可以快速、低成本地把想法變成一個(gè)實(shí)實(shí)在在的、可交互的應(yīng)用。
相比前幾章來(lái)說(shuō),這是一個(gè)更加復(fù)雜的應(yīng)用,因此我們每次只完成一項(xiàng)功能,從自動(dòng)回復(fù)開始。以下是將要學(xué)習(xí)的內(nèi)容:
Texting組件:具有收發(fā)短信功能;
TextBox組件:用于提交自定義回復(fù)信息(需要與Button組件配合使用);
TinyDB數(shù)據(jù)庫(kù)組件:用于保存自定義信息,即使應(yīng)用已經(jīng)關(guān)閉,信息也不會(huì)丟失;
Screen.Initialize事件:在應(yīng)用啟動(dòng)時(shí)加載自定義回復(fù)內(nèi)容;
Text-to-Speech組件:用于大聲朗讀文字;
本應(yīng)用的運(yùn)行,需要手機(jī)上Text-To-Speech(TTS)模塊的支持。該模塊包含在Android 2或更高的版本中,如果你的操作系統(tǒng)是Android 1.x,需要從Google Play下載。在手機(jī)上:
1. 打開Google Play應(yīng)用;
2. 搜索TTS;
3. 選擇應(yīng)用Text-To-Speech Extended并安裝。
TTS模塊安裝后,可以測(cè)試其功能。對(duì)于Android2以上版本,在"設(shè)置->輔助功能"中打開“文字轉(zhuǎn)換語(yǔ)音輸出”功能,根據(jù)需要設(shè)置默認(rèn)語(yǔ)言及語(yǔ)速,然后選擇“收聽示例”。如果沒聽到任何聲音,請(qǐng)確認(rèn)手機(jī)音量已調(diào)高;還可以更改TTS引擎默認(rèn)屬性設(shè)置,來(lái)改變聲音效果。
TTS模塊設(shè)置完成后,登陸App Inventor網(wǎng)站開始新項(xiàng)目“NoTextingWhileDriving”(項(xiàng)目名中不能有空格),然后設(shè)置屏幕的標(biāo)題為“開車不發(fā)短信”,最后通過WiFi與測(cè)試手機(jī)(AI伴侶)連接。
應(yīng)用的用戶界面很簡(jiǎn)單:一個(gè)顯示自動(dòng)回復(fù)內(nèi)容的Label,一個(gè)編輯自動(dòng)回復(fù)信息的文本輸入框和一個(gè)提交輸入結(jié)果的按鈕。還需要拖入一個(gè)Texting組件、一個(gè)TinyDB組件、一個(gè)TextToSpeech組件以及一個(gè)LocationSensor組件,這些組件都將出現(xiàn)在“不可視組件”區(qū)。你可以在圖4-2中看到上述組件在設(shè)計(jì)器中的截圖。
圖 4-2 組件設(shè)計(jì)器中的“開車不發(fā)短信”應(yīng)用
將表4-1中列出的組件拖到預(yù)覽窗口中,創(chuàng)建出圖4-2中所示的用戶界面。
表4-1 “開車不發(fā)短信”應(yīng)用中的全部組件
組件類型 | 面板中分組 | 命名 | 作用 |
---|---|---|---|
Label | User Interface | PromptLabel | 讓用戶了解應(yīng)用的功能 |
Label | User Interface | ResponseLabel | 顯示即將發(fā)送的自動(dòng)回復(fù)信息 |
TextBox | User Interface | NewResponseTextbox | 用戶在此處輸入定制的回復(fù)信息 |
Button | User Interface | SubmitResponseButton | 用戶點(diǎn)擊來(lái)提交、保存回復(fù)信息 |
Texting | Social | Texting1 | 處理短信事務(wù) |
TinyDB | Storage | TinyDB1 | 將自動(dòng)回復(fù)信息保存在數(shù)據(jù)庫(kù)中 |
TextToSpeech | Media | TextToSpeech1 | 大聲朗讀來(lái)信 |
LocationSensor | Sensors | LocationSensor1 | 感知電話所在位置 |
按照以下方式設(shè)置組件屬性:
設(shè)置PromptLabel的Text屬性為“當(dāng)本應(yīng)用正在運(yùn)行時(shí),將用下面的文字來(lái)回復(fù)所有收到的短信?!?/p>
設(shè)置ResponseLabel的Text屬性為“我正在開車,稍后與您聯(lián)系?!辈⒐催xFontBold(粗體字)屬性;
設(shè)置NewResponseTextbox的Text屬性為“”(讓文本框?yàn)榭眨却脩糨斎耄?/p>
設(shè)置NewResponseTextbox的Hint(提示)屬性為“輸入新的回復(fù)內(nèi)容”,Width設(shè)為“Fill Parent”;
從基本的自動(dòng)回復(fù)行開始,再逐步添加更多功能。
自動(dòng)回復(fù)功能需要用到App Inventor的Texting組件,可以把它想象成一個(gè)藏在手機(jī)里的小矮人,它知曉如何收發(fā)短信。該組件用Texting.MessageReceived事件塊來(lái)響應(yīng)“收到短信”,拖出該事件塊,并在塊內(nèi)放入一些命令塊,看看當(dāng)你收到短信時(shí),會(huì)發(fā)生什么事情。這里我們希望能夠自動(dòng)回復(fù)預(yù)先編輯好的內(nèi)容。
發(fā)送短信的操作需要調(diào)用Texting1.SendMessage塊,將其放在Texting1.MessageReceived塊內(nèi)。Texting1.SendMessage塊只能發(fā)送短信,至于要發(fā)什么內(nèi)容,以及發(fā)給誰(shuí),需要在調(diào)用之前,由你來(lái)告訴它:表4-2列出了自動(dòng)回復(fù)行為所需要的塊,而圖4-3顯示了它們?cè)趬K編輯器中的樣子。
**表4-2 自動(dòng)回復(fù)短信所需要的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
Texting1.MessageReceived | Texting | 手機(jī)收到短信時(shí)會(huì)啟動(dòng)該事件的處理程序 |
set Texting1.PhoneNumber to | Texting | 在發(fā)送短信前設(shè)置接收者電話號(hào)碼 |
get number | Variables | 獲取短信發(fā)送者的電話號(hào)碼 |
set Texting.Message to | Texting | 設(shè)置要發(fā)送的短信內(nèi)容 |
ResponseLabel.Text | ResponseLabel | 用戶預(yù)輸入的短信內(nèi)容 |
call Texting1.SendMessage | Texting | 發(fā)送短信 |
圖 4-3 對(duì)收到的短信進(jìn)行自動(dòng)回復(fù)
手機(jī)收到短信將觸發(fā)Texting1.MessageReceived事件。如圖4-3所示,發(fā)送者的手機(jī)號(hào)保存在參數(shù)number中,短信內(nèi)容保存在參數(shù)messageText中。自動(dòng)回復(fù)就是要向發(fā)送者發(fā)送一條短信,為此要先設(shè)置Texting組件的兩個(gè)關(guān)鍵屬性:PhoneNumber及Message。PhoneNumber設(shè)置為發(fā)送者的手機(jī)號(hào),Message設(shè)置為ResponseLabel中顯示的內(nèi)容:“我正在開車,稍后與您聯(lián)系。”設(shè)置完成之后,調(diào)用Texting. SendMessage實(shí)現(xiàn)自動(dòng)回復(fù)。
注釋是編程工作的重要組成部分,它可以告訴其他程序員那些與代碼有關(guān)的重要信息。在塊上單擊右鍵,在快捷菜單中選擇“Add Comment”(添加注釋),此時(shí)塊的左上方會(huì)出現(xiàn)藍(lán)色問號(hào),點(diǎn)擊藍(lán)色問號(hào),會(huì)彈出文本輸入框,可供輸入注釋信息;點(diǎn)擊藍(lán)色問號(hào)還可以隱藏注釋信息。注釋在應(yīng)用中不是必須的,這里添加注釋是為了介紹每個(gè)塊的功能。
很多人用注釋來(lái)記錄創(chuàng)建應(yīng)用的過程;注釋可以解釋程序的功能,但不會(huì)改變程序的行為。無(wú)論是你自己今后要修改程序,還是其他人要對(duì)程序做個(gè)性化設(shè)置,注釋都是非常重要的。“沒有不變的軟件”已經(jīng)成為共識(shí),因此,代碼的注釋是軟件工程中非常重要的環(huán)節(jié),尤其像App Inventor這樣的開源軟件。
測(cè)試: 需要用第二部手機(jī)來(lái)測(cè)試程序。如果沒有,可以注冊(cè)申請(qǐng)Google Voice或其他類似的服務(wù),并從注冊(cè)的服務(wù)中給你的手機(jī)發(fā)送短信。用第二部手機(jī)給正在運(yùn)行本應(yīng)用的手機(jī)發(fā)短信,第二部手機(jī)是否收到了回信?
下面來(lái)添加更多的程序塊,允許用戶輸入自定義的回復(fù)內(nèi)容。在組件設(shè)計(jì)器中,已經(jīng)添加了名為NewResponseTextbox的TextBox組件,用于輸入自定義回復(fù)信息,當(dāng)用戶點(diǎn)擊SubmitResponseButton時(shí),NewResponseTextbox中的內(nèi)容被復(fù)制到ResponseLabel中,這就是自動(dòng)回復(fù)短信的內(nèi)容。表4-3列出了在ResponseLabel中顯示新的回復(fù)內(nèi)容所需的塊。
表4-3 顯示自定義回復(fù)所需的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
SubmitResponseButton.Click | SubmitResponseButton | 點(diǎn)擊按鈕提交新的回復(fù)信息 |
set ResponseLabel.Text to | ResponseLabel | 為該Label設(shè)置新的文本內(nèi)容 |
NewResponseTextbox.Text | NewResponseTextbox | 用戶在這里輸入新的回復(fù)內(nèi)容 |
一個(gè)典型的輸入表單 的作用是:首先在文本框中輸入文字,然后單擊提交按鈕來(lái)通知系統(tǒng)做處理。圖4-4顯示了用戶點(diǎn)擊“修改回復(fù)內(nèi)容”按鈕時(shí), SubmitResponseButton.Click事件被觸發(fā)。
圖 4-4 將用戶輸入的信息設(shè)置為自動(dòng)回復(fù)內(nèi)容
事件處理程序?qū)⒂脩粼贜ewResponseTextbox中輸入的文字復(fù)制到ResponseLabel中,而ResponseLabel保存的是自動(dòng)回復(fù)信息,因此要確保新輸入的信息顯示在ResponseLabel中。
測(cè)試:輸入一段自定義信息并提交,然后用第二部手機(jī)發(fā)送短信到測(cè)試手機(jī)上,看看這次自動(dòng)回復(fù)的是新定制的內(nèi)容嗎?
你創(chuàng)建了一個(gè)偉大的應(yīng)用,卻留下了一個(gè)陷阱:用戶輸入了定制回復(fù),然后關(guān)閉應(yīng)用,當(dāng)再次啟動(dòng)應(yīng)用時(shí),定制回復(fù)卻不見了(取而代之的是默認(rèn)回復(fù))。這種狀況可不是用戶所期望的,他們希望在重啟應(yīng)用時(shí),定制的內(nèi)容還在,為此需要信息的永久保存。
你可能認(rèn)為數(shù)據(jù)放在ResponseLabel組件的Text屬性中,也應(yīng)該算作“儲(chǔ)存”,但實(shí)際上組件屬性中的數(shù)據(jù)是臨時(shí)數(shù)據(jù),就像人的短時(shí)記憶,只要應(yīng)用關(guān)閉,數(shù)據(jù)就會(huì)被“忘記”。如果希望應(yīng)用能永久記住某些數(shù)據(jù),就需要將數(shù)據(jù)從短時(shí)記憶(組件的屬性或變量)轉(zhuǎn)移到永久記憶中(數(shù)據(jù)庫(kù))。
要永久地保存數(shù)據(jù),需要使用TinyDB組件,它可以將數(shù)據(jù)存儲(chǔ)在Android設(shè)備內(nèi)置的數(shù)據(jù)庫(kù)中。TinyDB提供兩個(gè)功能: StoreValue(保存值)和getValue(獲取值)。前者允許應(yīng)用將信息存儲(chǔ)在設(shè)備數(shù)據(jù)庫(kù)中,而后者則允許應(yīng)用重新讀取已存儲(chǔ)的信息。
對(duì)于多數(shù)應(yīng)用,可以采取如下策略:
1. 每當(dāng)用戶提交新值,將其存儲(chǔ)到數(shù)據(jù)庫(kù);
2. 應(yīng)用啟動(dòng)時(shí),從數(shù)據(jù)庫(kù)中加載數(shù)據(jù)并將其賦給一個(gè)變量或?qū)傩浴?/p>
為了實(shí)現(xiàn)數(shù)據(jù)的永久保存,必須修改SubmitResponseButton.Click事件處理程序,表4-4中列出了所需要的程序塊。
表4-4 用TinyDB數(shù)據(jù)庫(kù)存儲(chǔ)定制回復(fù)所需要的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
TinyDB1.StoreValue | TinyDB1 | 將用戶的定制信息保存在手機(jī)內(nèi)置的數(shù)據(jù)庫(kù)中 |
”responseMessage” | Text | 以此作為保存數(shù)據(jù)的標(biāo)簽 |
ResponseLabel.Text | ResponseLabel | 已設(shè)定的回復(fù)信息顯示在這里 |
TinyDB從ResponseLabel的Text屬性中提取內(nèi)容,并將其保存在數(shù)據(jù)庫(kù)中。如圖4-5所示,向數(shù)據(jù)庫(kù)中保存數(shù)據(jù)時(shí),要為數(shù)據(jù)設(shè)置一個(gè)tag(標(biāo)簽),本例中的tag是“responseMessage”??梢园裻ag想象成數(shù)據(jù)在數(shù)據(jù)庫(kù)中的存放地址,是數(shù)據(jù)的唯一標(biāo)識(shí)。在下節(jié)中你將看到,必須使用相同的tag(“responseMessage”)才能將數(shù)據(jù)從數(shù)據(jù)庫(kù)中讀取出來(lái)。
圖 4-5 永久保存自定義回復(fù)信息
將定制回復(fù)信息保存在數(shù)據(jù)庫(kù)中,以便用戶再次啟動(dòng)應(yīng)用時(shí),保存的數(shù)據(jù)可以被重新讀取出來(lái)。App Inventor提供了一個(gè)特殊的事件塊:Screen1.Initialize,當(dāng)應(yīng)用啟動(dòng)時(shí),將觸發(fā)該事件(我們?cè)诘?章MoleMash中使用過)。將Screen.Initialize塊拖出來(lái),并將某些程序塊放在其中,那么這些程序塊會(huì)在應(yīng)用啟動(dòng)時(shí)逐一執(zhí)行。
在本應(yīng)用中,Screen1.Initialize事件的處理程序會(huì)檢查數(shù)據(jù)庫(kù)中是否存放了自定義回復(fù)內(nèi)容。如果是,則使用TinyDB.GetValue函數(shù)加載存儲(chǔ)的內(nèi)容。實(shí)現(xiàn)這一功能所需的塊見表4-5。
表4-5 應(yīng)用啟動(dòng)時(shí)用于加載數(shù)據(jù)的塊
組件類型 | 所在抽屜 | 作用 |
---|---|---|
Initialize global response to | Variables | 用于存放數(shù)據(jù)庫(kù)中讀出的定制回復(fù)信息 |
“” | Text | 變量的初始值可以是任意值 |
Screen1.Initialize | Screen1 | 應(yīng)用啟動(dòng)時(shí)會(huì)觸發(fā)該事件 |
set global response to | Variables | 用從數(shù)據(jù)庫(kù)中讀出的值為該變量賦值 |
TinyDB1.GetValue | TinyDB1 | 從數(shù)據(jù)庫(kù)中讀取已存儲(chǔ)的定制回復(fù)信息 |
"responseMessage" | Text | 插入TinyDB.GetValue的tag插槽,與之前TinyDB.StoreValue使用相同文本 |
If | Control | 判斷讀出的數(shù)據(jù)中是否包含文字 |
> | Math | 檢查讀出的數(shù)據(jù)長(zhǎng)度是否大于0 |
Length(text) | Text | 檢查文本類型數(shù)據(jù)的長(zhǎng)度 |
get global response | Variables | 從變量中讀出的數(shù)據(jù)(定制回復(fù)信息) |
數(shù)字0 | Math | 用于比較長(zhǎng)度 |
uuset ResponseLabel.Text to | ResponseLabel | 如果讀出的數(shù)據(jù)有內(nèi)容,放在label中 |
get global response | Variables | 從變量中讀出的數(shù)據(jù)(定制回復(fù)信息) |
如圖4-6所示,要想理解這些塊的功能,必須設(shè)想用戶的使用過程:首次打開應(yīng)用,輸入自定義回復(fù),隨時(shí)退出并再次打開應(yīng)用。用戶首次啟動(dòng)應(yīng)用時(shí),數(shù)據(jù)庫(kù)中沒有定制回復(fù)可供加載,因此ResponseLabel中顯示的是默認(rèn)回復(fù)。再次啟動(dòng)時(shí),才有可能從數(shù)據(jù)庫(kù)中加載定制回復(fù),并將其顯示在ResponseLabel中。
圖 4-6 應(yīng)用啟動(dòng)時(shí)從數(shù)據(jù)庫(kù)中加載定制回復(fù)
應(yīng)用啟動(dòng)時(shí)觸發(fā)Screen1.Initialize事件,并用tag “responseMessage”來(lái)調(diào)用TinyDB1.GetValue,該tag與之前用戶存儲(chǔ)定制回復(fù)時(shí)采用的tag相同。讀出的值放在變量response中,并對(duì)其進(jìn)行檢驗(yàn),然后才能在ResponseLabel中顯示。想想看,為什么從數(shù)據(jù)庫(kù)中讀出的數(shù)據(jù),在向用戶顯示之前,要經(jīng)過檢驗(yàn)?zāi)兀咳绻麛?shù)據(jù)庫(kù)中不存在與指定tag相對(duì)應(yīng)的數(shù)據(jù),TinyDB將返回空文本;而第一次啟動(dòng)應(yīng)用時(shí),數(shù)據(jù)是不存在的,直到用戶輸入了自定義回復(fù),數(shù)據(jù)才會(huì)有。由于變量response中保存了數(shù)據(jù)庫(kù)返回值,因此可以用if塊來(lái)檢查其長(zhǎng)度是否大于0。如果大于0 ,說(shuō)明的確從TinyDB讀出了定制回復(fù)信息,就會(huì)將信息顯示在ResponseLabel中;如果長(zhǎng)度不大于0,說(shuō)明之前沒有保存過定制回復(fù)信息,因此將不修改ResponseLabel的顯示內(nèi)容(保留默認(rèn)自動(dòng)回復(fù)內(nèi)容)。
測(cè)試:上述功能無(wú)法進(jìn)行實(shí)時(shí)測(cè)試,因?yàn)槊看芜B接“AI伴侶”啟動(dòng)應(yīng)用時(shí),數(shù)據(jù)庫(kù)都會(huì)被清空。因此需要選擇“build->App(provide QR code)”,然后掃描條碼,將應(yīng)用下載安裝到手機(jī)上。安裝之后,在NewResponseTextbox中輸入新的回復(fù)信息并單擊SubmitResponseButton按鈕;關(guān)閉應(yīng)用并重新啟動(dòng)它,這次定制回復(fù)信息出現(xiàn)了嗎?
本節(jié)將修改應(yīng)用:收到短信后,手機(jī)將大聲朗讀發(fā)送者的電話號(hào)碼以及短信內(nèi)容。開車收到短信,雖然有自動(dòng)回復(fù)功能,但你還是禁不住想知道短信的內(nèi)容。使用text-to-speech功能,就可以手不離方向盤而收聽到短信的內(nèi)容。
Android設(shè)備提供了text-to-speech功能,而App Inventor提供了一個(gè)TextToSpeech組件,它可以讀出任何text(文本信息 )(注意,此處“text”指的是一般意義上的字/word:一串字母、數(shù)字以及標(biāo)點(diǎn)符號(hào)組成的文本,而不是短信文本 。)
在本章的“準(zhǔn)備開始”部分,我們要求你從Android Market下載一個(gè)text-to-speech的模塊。如果你還沒做,現(xiàn)在該去做了。根據(jù)需要安裝并配置完模塊之后,就可以在App Inventor中使用TextToSpeech組件了。
TextToSpeech組件的使用非常簡(jiǎn)單,只需調(diào)用它的Speak函數(shù)并插入要朗讀的文字即可。例如,圖4-7中的函數(shù)會(huì)說(shuō)“Hello World”。
圖 4-7 會(huì)說(shuō)“HelloWorld”的塊
在本應(yīng)用中,朗讀的內(nèi)容則更為復(fù)雜,既要包含短信發(fā)送者的電話號(hào)碼,也要包含短信內(nèi)容,而不只是像“Hello World”那樣的靜態(tài)文本。這里要用到極為重要的join塊,它可以將若干文本片段(或數(shù)字以及其他字符)連接成單一的文本對(duì)象。
在之前的Texting.MessageReceived事件處理程序中,加入對(duì)TextToSpeech.Speak的調(diào)用。在之前的事件處理程序中,通過適當(dāng)設(shè)置Texting組件的PhoneNumber和Message屬性,然后發(fā)送回復(fù)信息?,F(xiàn)在需要加入表4-6中所列出的塊來(lái)擴(kuò)展該事件的處理程序。
表4-6 朗讀收到的短信所需的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
TextToSpeech1.Speak | TextToSpeech1 | 大聲讀出收到的短信 |
join | Text | 連接生成將被朗讀的文字 |
"SMS text received from" | Text | 被讀出的第一段話 |
get number | Variables | 獲得短信發(fā)送者的電話號(hào)碼 |
". The message is" | Text | 在讀完電話號(hào)碼之后稍加停頓,然后說(shuō)"The message is" |
get messageText | Variables | 獲得收到的短信文本 |
在自動(dòng)回復(fù)動(dòng)作完成之后,將調(diào)用TextToSpeech1.Speak函數(shù),如圖4-8的下半部分所示。你可以在TextToSpeech1.Speak函數(shù)的消息槽中插入任何文本對(duì)象。在這種情況下,join塊用來(lái)生成被讀出的內(nèi)容。它將幾段文字串連在一起,最后生成類似這樣的信息:“SMS text received from 111-222-3333. The message is:hello.”
圖 4-8 大聲讀出收到的短信
測(cè)試:你需要第二部手機(jī)來(lái)測(cè)試應(yīng)用。用第二部手機(jī)發(fā)送文字【必須是英文】到你的測(cè)試手機(jī)上。你的手機(jī)大聲讀出信息了嗎?它是否照常發(fā)送自動(dòng)回復(fù)?
像Facebook的Places以及Google的Latitude等類型的應(yīng)用,都是利用GPS信息來(lái)幫助人們跟蹤彼此的位置信息。這樣的應(yīng)用最令人擔(dān)憂的是隱私問題,原因之一是它引發(fā)了人們對(duì)“老大哥”的恐懼,這里的“老大哥”指的是那些設(shè)法跟蹤其公民下落的集權(quán)政府。但是使用位置信息的應(yīng)用的確非常有用,試想一個(gè)迷路的小孩,或者那些在森林里迷路的徒步旅行者。
在“開車不發(fā)短信”的應(yīng)用中,位置跟蹤讓回復(fù)的短信再多一點(diǎn)內(nèi)容,而不只是“我正在開車”,回復(fù)的信息可以是這樣的:“我正在北京東直門內(nèi)大街209號(hào)開車”。對(duì)于那些正在等待朋友或家人到來(lái)的人來(lái)說(shuō),這些額外的信息非常有益。
App Inventor提供了LocationSensor(位置傳感器)組件,作為手機(jī)的GPS (Global Positioning System全球定位系統(tǒng))功能的接口。除了緯度和經(jīng)度信息,LocationSensor也可以接入到谷歌地圖,為司機(jī)提供當(dāng)前位置的地址信息。
值得注意的是,LocationSensor并不總在讀取信息,因此務(wù)必要恰當(dāng)?shù)厥褂眠@一組件。具體地講,應(yīng)用只對(duì)LocationSensor.LocationChanged事件做出響應(yīng),而兩種情況會(huì)觸發(fā)LocationChanged事件:①當(dāng)手機(jī)的位置傳感器第一次收到位置信息時(shí);②隨著手機(jī)的移動(dòng),產(chǎn)生新的位置信息時(shí)。使用表4-7中列出的塊,具體方法是:當(dāng)LocationChanged事件觸發(fā)時(shí),將當(dāng)前地址信息保存到變量lastKnownLocation中,再將變量值插入到自動(dòng)回復(fù)信息中。
表4-7設(shè)置位置傳感器的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
Initialize global lastKnownLocation to | Variables | 創(chuàng)建一個(gè)變量來(lái)保存最后讀取的地址信息 |
"未知" | Text | lastKnownLocation的默認(rèn)值 |
LocationSensor1.LocationChanged | LocationSensor1 | 位置傳感器第一次讀到位置信息,或每次位置信息變化時(shí)觸發(fā)該事件 |
set global lastKnownLocation to | Variables | 設(shè)置變量值,稍后會(huì)用到 |
LocationSensor1.CurrentAddress | LocationSensor1 | 當(dāng)前地址信息,如:"北京市東城區(qū)東直門內(nèi)大街209號(hào)" |
當(dāng)位置傳感器首次讀取位置信息時(shí),LocationSensor1.LocationChanged事件被觸發(fā),隨著設(shè)備的移動(dòng),還會(huì)生成新的位置信息,事件將被再次觸發(fā)。由于自動(dòng)回復(fù)信息中要包括地址信息,因此,通過調(diào)用LocationSensor1.CurrentAddress函數(shù) 來(lái)獲取地址信息,并將其保存在lastKnownLocation變量中,如圖4-9所示。在后臺(tái),這個(gè)函數(shù)會(huì)調(diào)用谷歌地圖(通過API 來(lái)調(diào)用,將在第24章學(xué)到),并根據(jù)傳感器獲得的經(jīng)緯度信息來(lái)確定最近的街區(qū)地址。
圖 4-9 每當(dāng)傳感器收到GPS位置信息時(shí),用變量記錄手機(jī)的位置
注意,這些塊只完成了一半的工作,還要將位置信息插入自動(dòng)回復(fù)信息中,再回復(fù)給發(fā)件人。
用變量lastKnownLocation中的值對(duì)Texting1.MessageReceived事件處理程序加以修改,向自動(dòng)回復(fù)信息中添加位置信息。表4-8列出了所需要的塊。
表4-8在自動(dòng)回復(fù)中顯示位置信息的塊
塊的類型 | 所在抽屜 | 功能 |
---|---|---|
join | Text | 多段文本的連接器 |
ResponseLabel.Text | ResponseLabel | 不包含位置信息的定制回復(fù)信息 |
“我最后的位置在:” | Text | 原定制信息之后的位置信息提示詞 |
global lastKnownLocation | Variables | 地址信息,如:“北京市東城區(qū)東直門內(nèi)大街209號(hào)” |
向回復(fù)中添加位置信息需要LocationSensor1.LocationChanged事件與變量lastKnownLocation的協(xié)作。如圖4-10所示,并非直接發(fā)送ResponseLabel.Text中的信息,而是使用join塊將若干段信息整合起來(lái):原有的自動(dòng)回復(fù)信息+“ 我的最后位置在:”+變量lastKnownLocation。
圖 4-10 在回復(fù)信息中加入位置信息
變量lastKnownLocation的默認(rèn)值是“未知”,所以如果位置傳感器尚未產(chǎn)生位置信息,則自動(dòng)回復(fù)的第二部分內(nèi)容為“我的最后位置在:未知”。如果已經(jīng)產(chǎn)生了位置信息,則自動(dòng)回復(fù)的第二部分內(nèi)容有可能是這樣:“我的最后位置在:北京市東城區(qū)東直門內(nèi)大街209號(hào)”
測(cè)試:用第二部手機(jī)發(fā)送短信到運(yùn)行應(yīng)用的手機(jī)上,第二個(gè)手機(jī)是否接收到了帶有位置信息的自動(dòng)回復(fù)?如果沒有,請(qǐng)確保你已經(jīng)開啟了第一部手機(jī)的GPS定位功能。
圖4-11中顯示了“開車不發(fā)短信”最終的塊的配置
圖 4-11 完整的“開車不發(fā)短信”應(yīng)用(同時(shí)顯示所有注釋)
當(dāng)應(yīng)用已經(jīng)付諸使用,你也許會(huì)想到做一些改進(jìn),例如:
編寫另一個(gè)版本,允許用戶針對(duì)某些特定來(lái)信號(hào)碼定制回復(fù)內(nèi)容。你需要增加一個(gè)條件(if)塊,來(lái)檢查這些來(lái)信的手機(jī)號(hào)。有關(guān)條件塊(if)的更多信息,請(qǐng)參見第18章;
再編寫一個(gè)版本,根據(jù)用戶是否在某個(gè)緯度/經(jīng)度范圍內(nèi),來(lái)回復(fù)定制信息。這樣,如果應(yīng)用判斷你在房間222,它會(huì)回復(fù)“鮑勃在222房間,現(xiàn)在不能回復(fù)短信。”有關(guān)LocationSensor以及確定邊界的更多信息,請(qǐng)參見第23章;
下面是本章涉及到的一些概念:
Texting組件:既可以用來(lái)發(fā)短信,也可以處理收到的信息。在調(diào)用Texting.SendMessage之前,需要為Texting組件設(shè)置PhoneNumber及Message屬性。為了回復(fù)收到的短信,需要為Texting.MessageReceived事件編寫處理程序;
TinyDB組件:用于將信息永久存儲(chǔ)在手機(jī)數(shù)據(jù)庫(kù)中,以便每次應(yīng)用啟動(dòng)時(shí)都可以加載保存過的數(shù)據(jù)。有關(guān)TinyDB的更多信息,請(qǐng)參見第22章;
TextToSpeech組件:對(duì)于所提供的任何文本對(duì)象,都可以大聲朗讀出來(lái)(限英文);
join塊:用于將若干片段的文字拼湊(或連接)成單一的文本對(duì)象中;
Text-To-Speech
縮寫為TTS,直譯為“從文本到語(yǔ)音”,是語(yǔ)音合成技術(shù)的一種應(yīng)用,可以將文字信息實(shí)時(shí)轉(zhuǎn)換為語(yǔ)音。在本章中使用了Android設(shè)備的此項(xiàng)功能,但遺憾的是,目前Google的TTS引擎尚不支持中文的轉(zhuǎn)換,因此學(xué)員測(cè)試時(shí)還需使用英文。
text: 文本[名詞]
text: 發(fā)短信[動(dòng)詞]
initialize: 初始化
speech: 講話
location: 位置
sensor: 傳感器
tiny: 微小的
DB: database數(shù)據(jù)庫(kù)
social: 社交的
storage: 存儲(chǔ)
prompt: 提示
response: 響應(yīng)
receive: 接收
submit: 提交
hint: 提示
variable: 變量
phone: 電話
number: 數(shù)字,號(hào)碼
call: 調(diào)用,呼叫
message: 消息
send: 發(fā)送
add: 增加
comment: 注釋,評(píng)論
voice: 聲音
store: 存放
value: 值
tag: 標(biāo)簽
global: 全球的,全局的
control: 控制
math: 數(shù)學(xué)
length: 長(zhǎng)度
provide: 提供
code: 編碼
GPS: 全球定位系統(tǒng)(Global Positioning System)
change: 改變
last: 最后的
current: 當(dāng)前的,現(xiàn)在的
更多建議: