天天看點

《Android應用開發》——2.3節意圖類

本節書摘來自異步社群《android應用開發》一書中的第2章,第2.3節意圖類,作者 【美】chris haseman,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

2.3 意圖類

android應用開發

一個意圖是一個類。在android平台上,意圖構成了主要的通信協定,用來在應用構件之間傳輸資訊。在一個設計良好的android應用中,構件(活動、内容提供方或服務)永遠不該直接通路其他任何構件的執行個體。同樣,意圖是這些構件之間的通信方式。

本書原本可以用大半篇幅來介紹意圖類的建立、使用和細節。但為了簡潔并讓一切盡快地運轉起來,本章隻介紹幾個基本概念。可以到本書的其他章節尋找意圖的相關内容,它們可能是整個android平台中最常用的類。

有以下兩種主要方法可以告訴android系統,願意接收由系統、其他應用甚至使用者自己的應用所發出的意圖。

在androidmanifest.xml檔案中注冊一個。

在系統中注冊一個intentfilter運作時對象。

這兩種情況都需要告訴android系統你監聽什麼事件。

同樣有一大堆方法可以發出意圖。可以把它們廣播給系統,或者可以讓它們面向一個特别的活動或服務。但是,要啟動一個服務或活動,它必須在清單檔案中注冊(此前示範如何啟動一個新活動的時候,介紹過一個這樣的例子)。

下面看看如何在實踐中使用意圖。

2.3.1 清單注冊

為什麼不在運作時刻注冊?如果一個意圖聲明為清單檔案的一部分,系統會啟動構件以便讓它接收。在運作時刻注冊假定了已經在運作中。由于這一點,無論何時想喚醒應用、讓它就某個事件采取行動,都要在清單檔案中聲明。如果隻有在應用運作時才能接收它,就在那個特别的構件啟動之後注冊一個intentfilter(在xml中聲明時是intent-filter,但在java代碼中是intentfilter)。

下面回到初始的應用,再看看清單檔案中活動的相應資料項。

android.intent.action.main聲明是告訴系統,這個活動是應用的主活動,不需要參數來啟動它。在清單檔案中隻把一個活動列為main,這是個好想法。由eclipse運作應用的時候,adb(android調試橋)也正是據此知道要啟動哪個活動。

android.intent.category.launcher類别是告訴系統,在手機的主應用面闆上單擊圖示時應該啟動封閉的活動。而且也是告訴android系統,想讓圖示出現在應用的啟動欄控件内。這是一個intent-filter的例子,由android的項目建立工具來建立。下面添加一個使用者自己的意圖。

2.3.2 添加一個意圖

如果跳過了2.2節中關于活動類的内容,現在正好可以回去浏覽一下代碼。在2.2節中介紹了如何聲明和啟動一個簡單的新活動。但沒有講的是,在清單檔案中聲明一個,可以讓系統通路這個活動。下面就這麼做。

在這段代碼中注冊了包含com.haseman.urple_pony_power動作的意圖,把intent-filter的類别設定為預設值。

下面就用這個看起來非常荒誕的動作串來示範一個論點(以免被人認為不夠嚴肅)——就是說,這個動作串唯一需要的條件是它對于這個特别構件的獨一無二性。

在2.2節中介紹了如何使用下列代碼來啟動新的活動。

這個方法是有效的,但有一個大的缺陷——它不能在應用的語境之外啟動。這使得“活動—意圖”模型所提供的最強大的特性之一失去了用處。這個特性是,手機上的任何應用如果有合适的意圖,都可以使用應用内部的構件。

既然已經把加入到示例項目的清單檔案中,就可以在任意位置用以下代碼啟動這個特殊的活動。

可以注意到,在這段代碼和上面的清單之間有一個非常重要的不同。在本例中建立這個意圖的時候,不需要傳遞進來一個context對象(即整體而言與系統進行通信所需要的資訊包)。這使得任何應用在了解了所需的意圖之後,可以啟動newactivity類。

(2)在onkeydown事件處理方法中添加以下粗體處理的代碼,以不同的方式啟動同一個活動。新的onkeydown方法将如下所示:

現在,在示例應用中按向下鍵的時候,會看到同一個活動使用在清單檔案中聲明的這個新的intent-filter來啟動。

如果把這個意圖的動作串拼寫錯了或者忘記在intent-filter中添加預設的類别,系統可能會産生一個android.content.activity notfoundexception異常。

如果建立了一個意圖,而系統無法把它連接配接到手機的清單檔案中所列舉的任何活動,則startactivity方法随時會抛出這個異常。

注冊intent-filter不隻是活動的權限。任何android應用構件都可以通過注冊使得當系統廣播一個意圖動作時會啟動該構件。

多個意圖,一個活動

一個活動可以注冊為接收任意多的事件。典型地,發送一個意圖等同于告訴這個活動“做這件事”。而“這件事”可能是從編輯一個檔案到顯示一個可能的檔案或動作清單的任何事情。 正如此前所述,限制活動的作用範圍很重要,是以隻注冊一個意圖通常是個好想法。但是,因為一個活動可以注冊不止一個意圖,是以更好的思路是在oncreate方法内調用getintent方法,檢查活動為什麼被啟動,以便采取正确的行動(調用getaction)。

2.3.3 在運作時刻監聽意圖

另一個方法是在運作時刻監聽意圖,它隻接收與應用有關的事件或者android系統自身廣播的事件。使用者開啟飛行模式時,活動願意顯示一個特别的螢幕或采取一個自定義的動作。為了實作這一點,需要建立一個臨時的intentfilter和一個内部的broadcastreceiver對象執行個體。

1.建立一個receiver對象

現在給myactivity類添加運作時刻的broadcastreceiver對象。可以猜到,一個broadcastreceiver是一個隻有一個onreceive方法的對象。将myactivity類修改為如下所示:

這段代碼建立了一個可以在活動内部局部通路的receiver對象。系統調用onreceive方法時,需要檢查意圖的動作是什麼。這是個好想法,因為broadcastreceiver可以注冊任意多的不同意圖。

接收想要找的事件時,要使用android的toast api在螢幕上顯示一條簡單的消息(這種情況下,顯示的是變量名為airplane_change的字元串的内容)。在實踐中,這個時機可能适合在螢幕上顯示資訊,表明應用需要網絡連接配接才能正确運作。

2.告訴android你想聽到什麼

既然已經建立了一個broadcastreceiver對象,就可以在系統中注冊它。下面先看實作的代碼,然後看發生了什麼。

android系統中,一個toast就是一條短消息,在螢幕底部彈出的一個小消息框内顯示給使用者。這參考了toast的原意——祝酒詞,即在幹杯之前所做的簡短發言。對toast來說,永遠是越短小越簡單越好。

再次強調,正是在sdk中初始的myactivity類中建立了項目。

(1)在oncreate方法中建立一個意圖過濾器,向其中添加動作intent.action_airplane_mode_changed。

(2)可以向這個意圖過濾器中添加任意多的動作。調用receiver時,需要弄清楚到底是哪個意圖調用getaction(),觸發了這個broadcastreceiver對象的onreceive方法。

(3)按住開關按鈕,測試這段代碼,會彈出一個包含幾個選項的對話框。

(4)開啟飛行模式。如果目前為止一切操作都正确,就會看到螢幕底部彈出一小條消息,内容是警示資訊。

這就是應用監聽系統狀态資訊的首要方式。采用這個工具,從電池狀态到無線廣播狀态,一切盡在掌握。查閱android sdk文檔可以找到更多相關内容,例如以什麼權限可以監控哪些活動。

3.結束監聽

對于建立的每個運作時刻的注冊,同樣需要登出。如果使用者隻有在活動可見的時候才願意接收事件,那麼最好用onpause方法來關閉接收。如果隻要活動在運作,即使它不可見也願意繼續監聽,那麼最好在ondestroy方法中登出。不管在哪個方法中結束監聽,隻要調用unregisterreceiver(由超類實作的一個方法),把此前建立的broadcastreceiver對象傳遞進去,如下所示:

4.建立自包含的broadcastreceiver對象

broadcastreceiver對象不一定存在于活動内部。如果想了解一個系統事件,可以注冊一個receiver,但在事件發生時可能不需要啟動整個應用。

broadcastreceiver可以自己注冊在标記下。

在實踐中,使用它們來接收可能不需要顯示給使用者的系統資訊。如果一個活動是不需要的,那麼啟動它之後結果卻把它關閉是非常消耗資源的,不如用一個receiver擷取廣播的意圖,而隻在必要時啟動活動。

5.處理互相沖突的活動

你可能會想,“如果同一個意圖注冊了不止一個活動會怎麼樣?”這是個很有趣的問題,android系統隻通過詢問使用者就可以解決它。

如果兩個活動在各自的清單檔案中監聽同一個意圖,而一個應用試圖用該意圖啟動一個活動,那麼系統會彈出一個菜單,列舉一個可能的應用清單,讓使用者從中選擇(見圖2.2)。

《Android應用開發》——2.3節意圖類

正是這種注冊相似意圖的功能使無縫互動成為可能,因為注冊了這個意圖的每個應用都在share菜單上擁有一項。單擊這個清單中的一項會啟動相應的已注冊活動,并把可以通路到這個圖檔的位置資訊作為額外資料來傳遞。那麼,什麼是額外資料?這個問題問得好。

2.3.4 移動自己的資料

意圖主要的特性之一是能夠打包一塊發送資料。一個活動永遠不應該直接操作另一個活動的存儲空間。但是,活動之間必須有辦法交流資訊。這種交流是在意圖的額外資料這一資料包的幫助下完成的。這個資料包可以包含任意多的“字元串—原語”對。描述這個概念的最佳方法可能是用代碼和一個例子。

前文介紹過如何使用一個基于動作的廣播意圖來啟動一個新的活動。在之前介紹過的onkeydown監聽方法中添加以下粗體處理的代碼。

這是在用意圖啟動一個活動之前向其中添加一個字元串負載。無論誰接收這個意圖,都能把這個字元串取出(假定它們知道這個串的存在),把它用在合适的地方。既然已經知道怎樣添加額外資料,下面看一個例子,在newactivity類的oncreate方法中擷取和使用這個串。

粗體處理的代碼段是在擷取這個意圖,它通過調用getintent方法來啟動newactivity。接下來要檢查這個意圖是否真的包含newbodytext這個額外資料。記住,這個意圖可能并未包含額外資料。如果這裡忘了檢查,很快就會發現應用淹沒在nullpointerexceptions異常之中。如果額外資料存在,就把它取出,将字元串設定為螢幕中的新文本。最後兩行代碼擷取一個指針,指向螢幕的文本視圖,并把顯示的文本變為額外資料的内容。現在不必考慮這個特殊操作的實作機制,後文會更詳細地介紹這個主題。

現在學會了如何注冊、建立和使用一個意圖的基本功能。我們知道,它們可以在清單檔案中注冊或在運作時刻注冊。手機上的任何應用都可以發送意圖,而同一個意圖可以注冊任意多的應用構件。

本小節的目标是開始關注和了解android系統的意圖。在後面的章節中,會在多種不同的語境下使用意圖。

繼續閱讀