本節書摘來自異步社群《android開發秘籍(第2版)》一書中的第2章,第2.3節多個activity,作者 【美】ronan schwarz , phil dutson , james steele , nelson to,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視
2.3 多個activity
android開發秘籍(第2版)
就算是最簡單的應用程式也會擁有不止一項功能,是以我們經常要應對多個activity。例如,一款遊戲可能含有兩個activity,其一為高分排行榜,另一為遊戲畫面。一個記事本可以有三個activity:浏覽筆記清單、閱讀標明筆記、編輯標明的或建立的筆記。
androidmanifest.xml檔案中定義的主activity會随應用程式啟動而啟動。該activity可以開啟另外的activity,通常由觸發事件引起。這第二個activity被激活時,主activity會暫停。當第二個activity結束時,主activity會被重新調回前台恢複運作。
要想激活應用中的某個特定元件,可以用顯式命名該元件的intent來實作。而應用程式的所需可以通過intent過濾器指定,這時可采用隐式intent。系統可随即确定最合适的某個或某組元件,不管它是屬于另外的應用還是系統自帶的。注意,與其他activity不同,位于其他應用程式中的隐式intent不需要在目前應用的androidmanifest.xml檔案中聲明。
android盡可能選用隐式intent,它能為子產品化功能提供強大的架構。當一個符合所需的隐式intent過濾器要求的新元件開發完成,它就可以替代android内部的intent。舉個例子,假如一個用來顯示電話聯系人的新應用被裝入到android裝置,當使用者選擇聯系人時,android系統會找出符合浏覽聯系人這一intent過濾器要求的所有可用的activity,并詢問使用者想使用哪一個。
技巧9:使用按鈕和文本視圖
觸發器事件有助于全面展示多activity特性。為此我們引入一個按鈕(button)按下動作,為給定的布局添加按鈕并為其指派動作的步驟如下。
(1)為指定的布局xml檔案添加一個按鈕控件:
為展示動作的效果,改變螢幕上的文字不失為一招。定義文本域并通過程式設計對其進行改動的步驟如下:
(1)用一個id為指定的布局xml檔案添加文本域,該文本域可以有初始值(此處可用strings.xml中定義的hello字元串初始化它)。
(2)聲明一個指向布局檔案中textview id的textview(文本視圖):
private textview tv = (textview) findviewbyid(r.id.hello_text);
(3)如果需要變更文本,可使用settext函數:
tv.settext("new text string");
以上兩項ui技術會在本章後續的一些技巧中用到。對于ui技術更詳細的講解請參見第5章。
技巧10:通過事件啟動另外一個activity
本技巧中menuscreen是主activity,如代碼清單2-9所示,它會開啟名為playgame的activity。此處,觸發器事件是作為按鈕點選、用button微件實作的。
當使用者點選按鈕,startgame()函數會運作,并啟動playgame activity。當使用者點選playgame activity中的按鈕時,它會調用finish()函數将控制權交還給調用它的activity。下面是啟動activity的步驟。
(1)聲明一個指向要啟動的activity的intent。
(2)在該intent上調用startactivity方法。
(3)在androidmanifest.xml中對這一額外的activity加以聲明。
代碼清單2-9 src/com/cookbook/launch_activity/menuscreen.java
在匿名内部類裡提供目前上下文環境
注意,通過點選按鈕啟動activity時,還有一些東西需要考慮,如代碼清單2-9顯示的那樣,intent需要一個上下文環境。然而,在onclick函數裡使用this引用并不是個穩妥的解決辦法。下面給出通過匿名内部類來提供目前上下文環境的幾種不同方法。
使用context.this代替this。
使用getapplicationcontext()代替this。
顯式地使用類名menuscreen.this。
調用一個在合适的上下文級别中聲明的函數。在代碼清單2-8的startgame()中使用的就是這個方法。
這些方法通常是可以互換的,可依照具體情況選擇最好的方法。
代碼清單2-10中給出的playgame activity隻不過是一個按鈕,帶有一個會調用finish()函數把控制權交還給主activity的onclick監聽器。可以按需給該activity添加更多的功能,各個代碼分支可以導緻各自不同的finish()調用。
代碼清單2-10 src/com/cookbook/launch_activity/playgame.java
playgame activity引用它自己的按鈕id——end_game,它位于布局資源r.layout.game中,r.layout.game又對應名為game.xml的xml檔案,如代碼清單2-12所示。
代碼清單2-12 res/layout/game.xml
盡管在各種情況下文本都可以顯式地寫在代碼中,但更好的編碼習慣是為每個字元串定義相應變量。本技巧裡,名為play_game和end_game的兩個字元串需要在字元串資源檔案中分别定義,如代碼清單2-13所示。
代碼清單2-13 res/values/strings.xml
最終,在androidmanifest.xml檔案裡需要為playgame這個新類注冊一個預設動作,如代碼清單2-14所示。
代碼清單2-14 androidmanifest.xml
技巧11:通過使用語音轉文本功能啟動一個activity
本技巧示範了如何調用一個activity以擷取其傳回值,還示範了如何使用google的recognizerintent中的語音轉文本功能,并将轉換結果輸出到螢幕上。這裡采用按鈕點選作為觸發事件,它會啟動recognizerintent activity,後者對來自麥克風的聲音進行語音識别,并将其轉換為文本。轉換結束時,文本會被傳遞回調用recognizerintent的activity。
傳回時,首先會基于傳回的資料調用onactivityresult()函數,然後會調用onresume()函數使activity正常繼續。調用的activity可能會出現問題而不能正确傳回,是以,在解析傳回的資料之前,應當始終檢查resultcode確定傳回值為result_ok。
注意,一般來講啟動任何會傳回資料的activity都将導緻同一個onactivityresult()函數被調用。是以,要使用一個請求代号來辨識是哪個activity在傳回資料。當被啟動的activity結束時,它會将控制權交還給調用它的activity,并使用相同的請求代碼調用onactivityresult()。
調用activity擷取傳回值的步驟如下:
(1)用一個intent調用startactivityforresult()函數,定義被啟動的activity及一個起識别作用的requestcode變量。
(2)重寫onactivityresult()函數,檢查傳回結果的狀況,檢查所期望的requestcode,并解析傳回的資料。
下面是使用recognizerintent的步驟:
(1)聲明一個動作為action_recognize_speech的intent。
(2)為該intent傳遞附加内容,至少extra_language_model是必需的,它可以被設定成language_model_free_form 或者language_model_web_search。
(3)傳回的資料包中包含可能與原始文本比對的字元串的清單。使用data.<code></code>getstringarraylistextra檢索這一資料,它将在稍後以arraylist的形式傳送給使用者。
傳回的文本用一個textview顯示。主activity在代碼清單2-15中給出。
所需的支援檔案還有main.xml和strings.xml,其中需要定義一個按鈕以及用于存放結果的textview,這可以借助技巧10中的代碼清單2-11和2-13來實作。androidmanifest.xml檔案中隻需要聲明主activity,這與前面的技巧1相同。recognizerintent activity是android系統原生的activity,不需要顯式聲明即可使用。
代碼清單2-15 src/com/cookbook/launch_for_result/recognizerintent example.java
技巧12:實作選擇清單
應用程式中常常需要提供給使用者一個選擇清單,供使用者點選。這一功能利用listactivity可以輕松地實作。listactivity是activity的一個子類,它會根據使用者選擇觸發事件。
下面是建立選擇清單的步驟。
這一技術在下一個技巧中也會用到。
技巧13:使用隐式intent建立activity
隐式intent不需要指定要使用哪個元件。相反,它們通過過濾器指定所需的功能,而android系統必須決定使用哪個元件是最佳選擇。intent過濾器可以是動作(action)、資料(data)或者分類(category)。
最常用的intent過濾器是動作,而其中最常用的要屬action_view。該模式需要指定一個統一資源辨別符(uri),進而将資料顯示給使用者。它為給定的uri執行最合理的動作。比如,在下面的例子中,case 0、case 1、case 2中的隐式intent擁有相同的文法,卻産生不同的結果。
下面是使用隐式intent啟動activity的具體步驟。
(1)聲明intent,同時指定合适的過濾器(如action_view、action_web_search等)。
(2)為運作activity所需的該intent附加額外的資訊。
(3)将該intent傳遞給startactivity()方法。
代碼清單2-16 src/com/cookbook/implicit_intents/listactivityexample.java
技巧14:在activity間傳遞基本資料類型
有時需要向某個啟動的activity傳遞資料,有時啟動的activity需要把其建立的資料傳回給調用它的activity。例如,需要把遊戲的最終得分傳回給高分排行榜界面。以下是在activity之間傳遞資訊的幾種不同方式。
在發起調用的activity中聲明相關變量(如public int finalscore),并在啟動的activity中為其指派(例如:callingactivity finalscore=score)。
給bundle附加額外資料(在本技巧中有所展現)。
使用preference屬性存儲資料,以備後面檢索(将在第6章中介紹)。
使用sqlite資料庫儲存資料,以備後面檢索(将在第11章中介紹)。
bundle是從字元串值到各種可打包(parcelable)類型的映射,可以通過向intent添加額外資料建立它。本技巧顯示了将資料從主activity傳遞給啟動的activity,在其中修改後再傳遞回來的全過程。
變量(本例中一個為integer型,另一個為string型)在startscreen activity中定義。在建立intent調用playgame類時,通過putextra方法把這兩個變量附加給intent。當結果從啟動的activity中傳回時,可借助getextras方法讀取變量值。以上調用過程如代碼清單2-17所示。
代碼清單2-17 src/com/cookbook/passing_data_activities/startscreen.java
傳入playgame activity的變量可以用getintextra和getstringextra讀取。當該activity結束并準備通過一個intent傳回時,可以用putextra方法将資料傳回給發起調用的activity。上述調用如清單2-18所示。
代碼清單2-18 src/com/cookbook/passing_data_activities/playgame.java
1裝置獨立/無關像素(device-independent pixels),簡寫為dip或dp,是android為友善跨不同螢幕類型的裝置的程式設計而推出的一種虛拟像素機關,用于定義應用的ui,以密度無關的方式表達布局尺寸或位置。在運作時,android根據使用中的螢幕的實際密度,透明地處理任何所需dip機關的縮放。在第5章的表5.1中也有涉及。——譯者注