Android應(yīng)用程序生命周期中的活動與圖標(biāo)
為您的 Android 移動應(yīng)用程序添加導(dǎo)航風(fēng)格
Activity 類是 Android 移動應(yīng)用程序的基礎(chǔ),您可以使用它來優(yōu)化應(yīng)用程序與用戶和移動設(shè)備的交互。讓應(yīng)用程序生命周期中的交互方式與您的期望完全一致,并使用圖標(biāo)與操作欄引導(dǎo)用戶使用 UI 導(dǎo)航與其他應(yīng)用程序功能。
簡介
如今移動設(shè)備的功能已經(jīng)強大到難以置信,比眾多開發(fā)人員用來編寫首個程序的桌面計算機還要強大得多。因此,大家很容易忘記移動設(shè)備仍然屬于資源有限的環(huán)境。 開發(fā)移動應(yīng)用程序時,決不能忘記運行應(yīng)用程序的環(huán)境所具有的局限性。尤其是當(dāng)應(yīng)用程序要與其他應(yīng)用程序競爭系統(tǒng)資源時 — 其中有些應(yīng)用程序?qū)τ谟脩舻娜粘P袨槎员饶膽?yīng)用程序更加重要。
確保應(yīng)用程序廣受歡迎的途徑之一是保證它節(jié)省系統(tǒng)資源。在 Android 中,使用和保持系統(tǒng)資源的機制都是 Activity
類。您越了解這個基本類(與 Java Servlet
十分相似)的生命周期,調(diào)整 Android 移動應(yīng)用程序的資源使用與性能的能力就越強。
我們將從快速了解 Activity
類生命周期開始。通過一個示例應(yīng)用的演示,您將了解處理 Android 應(yīng)用程序生命周期內(nèi)每個階段的方法。掌握這些方法協(xié)同工作的原理之后,就能聰明地使用系統(tǒng)資源。然后更新演示應(yīng)用程序的導(dǎo)航系統(tǒng),使用 操作圖標(biāo) 代替菜單按鈕來實現(xiàn)用戶交互。圖標(biāo)在移動應(yīng)用程序 UI 中是十分標(biāo)準(zhǔn)的,而較新的 Android 設(shè)備(版本 4.2.2 及更高的版本)已經(jīng)棄用了選項菜單,而改用操作欄。掌握如何將這些特性與您的 Android 移動應(yīng)用程序集成在一起將使您受益無窮!
Activity 類生命周期
Activity
的生命周期直接對應(yīng)著 Android 移動應(yīng)用程序的生命周期。當(dāng)用戶與應(yīng)用程序或運行應(yīng)用程序的設(shè)備進行交互時,Android 平臺將在 Activity
實例上執(zhí)行回調(diào)。當(dāng)用戶啟動應(yīng)用程序時,初始的 Activity
將執(zhí)行一個已定義的生命周期。當(dāng)應(yīng)用程序轉(zhuǎn)入后臺時,它執(zhí)行生命周期的一個不同階段,而當(dāng)應(yīng)用程序關(guān)閉時則執(zhí)行另一個階段。圖 1 顯示了每個交互階段的 Android Activity
生命周期。
圖 1. Android 的 Activity 生命周期
Android 移動應(yīng)用程序生命周期包含四個階段:
- 啟動
- 暫停與恢復(fù)
- 停止與重啟
- 銷毀
后面的內(nèi)容將會講述每個階段及其回調(diào)方法(可在 Activity
實例內(nèi)部實現(xiàn))。
Activity 生命周期中的啟動
在 前面的文章中,您已經(jīng)使用了對應(yīng)啟動 Activity
的回調(diào)方法,即 onCreate
。您可能也熟悉 onStart
與 onResume
,啟動時也會調(diào)用這兩個方法?,F(xiàn)在,在 Activity
生命周期的上下文中考慮這些方法。
在 Eclipse Android 開發(fā)環(huán)境中,選擇 Override/Implement Methods... 選項即可輕松重寫方法,如 圖 2 中所示。
圖 2. 重寫 Activity 生命周期回調(diào)方法
接下來,選擇 onStart
與 onResume
方法:
圖 3. 選擇回調(diào)
現(xiàn)在使用 Android 的 Log
類加入一些跟蹤語句,就像我在 清單 1 中所做的那樣。
清單 1. 實現(xiàn) Android Activity 回調(diào)
- @Override
- protected void onResume() {
- super.onResume();
- Log.d("overheardword", "onResume Invoked");
- }
- @Override
- protected void onStart() {
- super.onStart();
- Log.d("overheardword", "onStart Invoked");
- }
啟動應(yīng)用程序的一個實例并通過 LogCat 查看日志,對結(jié)果進行檢查,如 圖 4 中所示。
圖 4. LogCat 的調(diào)試語句
您很可能已經(jīng)猜到,首次加載應(yīng)用程序時將調(diào)用 onCreate
,而在其他階段的上下文中使用 onStart
與 onResume
更加方便,比如當(dāng)應(yīng)用程序轉(zhuǎn)入后臺和重啟時。
Activity 生命周期中的暫停與恢復(fù)
因 為移動設(shè)備通常會運行多個應(yīng)用程序,而它們會以各種方式來吸引用戶的注意力,因此您的應(yīng)用程序應(yīng)該知道何時讓另一個應(yīng)用程序占據(jù)設(shè)備屏幕并使用更多資源。 有時,用戶在使用應(yīng)用程序時需要接電話,或者是應(yīng)用程序可能會彈出一個對話框,比如信息請求或錯誤消息。上述每種操作都將部分地阻斷當(dāng)前的 Activity
。
當(dāng)一個 Activity
被部分阻斷時,將調(diào)用 onPause
方法。當(dāng)暫停的 Activity
重新獲得焦點時,將調(diào)用 onResume
。暫停與恢復(fù)表示受影響的活動被部分阻斷,而非完全隱藏。
當(dāng)應(yīng)用程序完全隱藏時,例如用戶打電話,還會調(diào)用 onPause
,但在這種情況下還會繼續(xù)調(diào)用 onStop
。當(dāng)應(yīng)用程序再次轉(zhuǎn)入前臺時,將先調(diào)用 onRestart
,再調(diào)用 onStart
,最后調(diào)用 onResume
。
下面解釋實現(xiàn) onPause
、onRestart
與 onStop
時發(fā)生的事情。如果您已經(jīng)有了本系列文章中使用的 Android 應(yīng)用程序,那么在代碼中添加一些日志語句,然后運行應(yīng)用程序。按下 Home 按鈕完全隱藏實例,然后單擊它的圖標(biāo)再次運行。您應(yīng)該看到調(diào)用了一系列方法。首先看到的是 onPause
,然后是 onStop
。 單擊圖標(biāo)重新運行應(yīng)用程序時,調(diào)用的方法依次是 onRestart
、onStart
和 onResume
。
銷毀 Activity
也是運行應(yīng)用程序的常規(guī)過程中會發(fā)生的事情。例如,可以調(diào)用 Activity
實例的 finish
方法來終止該實例。這里的關(guān)鍵在于,因為關(guān)閉了一個 Activity
,所以它將遵循與被隱藏相同的生命周期,但它最后會回調(diào) onDestroy
。
在 清單 2 中,我使用自己的 Overheard Word 應(yīng)用程序演示了這個過程,具體做法是在向上劃動手勢時調(diào)用了 finish
方法。
清單 2. 銷毀 Activity 實例
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- try {
- final SwipeDetector detector = new SwipeDetector(e1, e2, velocityX, velocityY);
- if (detector.isDownSwipe()) {
- return false;
- }else if (detector.isUpSwipe()) {
- finish();
- }else if (detector.isLeftSwipe()) {
- Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show();
- }else if (detector.isRightSwipe()) {
- Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
- }
- } catch (Exception e) {
- // nothing
- }
- return false;
- }
最常用的 Activity
生命周期方法是 onCreate
、onRestart
與 onDestroy
。例如,我使用了 onRestart
來刷新應(yīng)用程序 UI 視圖的眾多方面之一,并使用 onDestroy
釋放到數(shù)據(jù)庫的連接,比如 Android 設(shè)備上本地運行的 SQLite。
現(xiàn)在可能還不明顯,但一旦開始與外部資源協(xié)作 — 比如外部 Web 服務(wù)或設(shè)備的文件系統(tǒng)或數(shù)據(jù)庫 — 這些生命周期階段將變得十分重要。
接下來解釋如何使用兩個 Activity
hook 方法 —onCreateOptionsMenu
與 onOptionsItemSelected
— 實現(xiàn)應(yīng)用程序菜單行為。讓這兩個方法同步后,我們將把它們的功能連接到圖標(biāo),以實現(xiàn)額外的 UI 效果。
使用菜單與動作進行導(dǎo)航
當(dāng)我在 Eclipse 中創(chuàng)建 Overheard Word 項目時,定義的第一個 Activity
有一個存根方法 onCreateOptionsMenu
。正如您猜想的那樣,此方法用于創(chuàng)建一個選項菜單。在老式的 Android 設(shè)備上,選項菜單由 Menu 按鈕表示。在較新的設(shè)備上,它被表示為一系列垂直的點,顯示在應(yīng)用程序本身之中。較新的 Android 設(shè)備不一定有菜單按鈕。
在表示老式設(shè)備的模擬器實例中,有一個名為 "Menu" 的按鈕。只要單擊它,應(yīng)用程序?qū)嵗蜁@示選項菜單。在這個例子中,我們將看到用于導(dǎo)航的選項。例如,如果用戶按下 Home 按鈕,就會看到如 圖 5 中所示的內(nèi)容。
圖 5. 一個未實現(xiàn)的菜單項
平板電腦上沒有菜單按鈕。用戶無法從 菜單 中選擇項目,而是被要求發(fā)起各種 操作。這個較新的 UI 欄稱為 操作欄,如 圖 6 中所示。
圖 6. Android 的新操作欄
盡 管菜單按鈕與操作欄的行為方式很類似,但操作欄只在較新的設(shè)備上能實現(xiàn)。由于我們的目標(biāo)是老版本的 Android 系統(tǒng)(記住,約有 50% 的 Android 設(shè)備運行 Gingerbread?。?,因此我將使用更加熟悉的菜單按鈕進行演示。稍后,我將說明如何更新導(dǎo)航代碼以實現(xiàn)操作欄,滿足您以較新版本的 Android 及對應(yīng)設(shè)備為目標(biāo)的愿望。
創(chuàng)建一個選項菜單
為了翻新 Overheard Word 以提高用戶交互的效率,第一步最好是實現(xiàn)選項菜單,讓用戶能退出應(yīng)用程序。退出應(yīng)用程序是 Activity
生命周期的階段之一,因此我們將使用 Activity
方法實現(xiàn)這個功能。
記住,在 Android 應(yīng)用程序中,所有與 UI 相關(guān)的業(yè)務(wù)都對應(yīng)一個 XML 文件,因此定義 UI 的方法就是編輯布局的 XML 文件。Android 應(yīng)用程序的 XML 文件位于項目的 res
文件夾的特定目錄中(例如,布局文件位于 layout
目錄中)。
為了快速進行練習(xí),可以看一看 Overheard Word 主活動中 onCreateOptionsMenu
方法的默認實現(xiàn)方法 — 您看出了什么門道?
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.overheard_word, menu);
- return true;
- }
如果您正在考慮查找 menu
資源目錄中一個名為 overheard_word.xml
的 XML 文件,那么您就離成為一名 Android 專家不遠了!
我... 退出!
接下來,我們將編輯菜單資源 XML 文件,添加一個名為 quit
的菜單項。一開始需要在您的 res/values
目錄中找到 strings.xml
文件。找到之后,創(chuàng)建一個如下所示的新項:
<string name="quit_menu">Quit</string>
這個標(biāo)記定義了單詞 Quit,可以通過標(biāo)識符 quit_menu
來引用它(順便說一句,這對于應(yīng)用程序的國際化很有好處)。接下來,打開 menu
目錄中的 overheard_word.xml
文件。 在這個文件中,將標(biāo)題修改為 @string/quit_menu
,從而將單詞 Quit 鏈接到菜單項。
現(xiàn)在,啟動模擬器并按下 Menu 按鈕。應(yīng)該看到一個菜單出現(xiàn)在屏幕下方,其中有一個選項:Quit。但選擇它什么效果也沒有,因為目前還沒有實現(xiàn)它。
我們將在一分鐘內(nèi)為 Quit 選項添加實現(xiàn)代碼。但首先,我們要考慮移動應(yīng)用程序的任意功能部分的另一重要元素,即它的外觀。您可能已經(jīng)注意到,如今大量移動 UI(甚至越來越多的 Web 應(yīng)用程序 UI)都使用圖標(biāo)進行導(dǎo)航。下面將說明如何使用免費圖標(biāo)替換通用詞按鈕。
移動 UI 設(shè)計中的圖標(biāo)
在進入移動開發(fā)領(lǐng)域之前,我對圖標(biāo)也有涉獵,但很少在我的企業(yè)應(yīng)用程序中使用它們。當(dāng) Web 應(yīng)用程序的交互性開始變得更加突出時,我發(fā)現(xiàn)自己使用圖標(biāo)的次數(shù)也在增加。但直到我開始從事移動開發(fā),圖標(biāo)才真正成為我的工作重點。
如 果在 Android 移動 UI 設(shè)計中使用圖標(biāo),需要充分了解設(shè)備的分辨率。Android 設(shè)備生態(tài)系統(tǒng)非常龐大,您的應(yīng)用程序可能需要在各種設(shè)備上運行,從低分辨率的小屏設(shè)備一直到配備 7 英寸大屏的高分辨率平板電腦。一個在手持設(shè)備上顯示效果良好的圖標(biāo),在平板電腦上可能顯得十分粗糙。
幸運的是,您可以控制應(yīng)用程序圖標(biāo)在不同設(shè)備上的外觀??焖僭L問 Android 移動應(yīng)用程序的 res
目錄。您應(yīng)該可以看到一些名為 drawable-something-pdi
的目錄(這里的 "something" 是任意字母序列)。這些目錄對應(yīng)各種設(shè)備屏幕的分辨率。在這些目錄中放置大小正確的圖標(biāo)與其他圖像文件,可以確保您的圖標(biāo)在不同類型的設(shè)備上正確顯示。
例如,對于分辨率超高的設(shè)備,Android 將使用 drawable-xxhdpi
目錄中的圖標(biāo)。此目錄中的啟動圖標(biāo)應(yīng)該為 96 x 96 像素,并且至少為 320 dpi。drawable-ldpi
目錄中的啟動圖標(biāo)應(yīng)該為 36 x 26 像素和 120 dpi。您也可以選擇創(chuàng)建一個默認的 drawable
目錄,當(dāng) Android 無法找到指定圖標(biāo)分辨率對應(yīng)的文件時,將使用此目錄下的圖標(biāo)。
為了簡單起見,我將為我的 Overheard Word 應(yīng)用程序創(chuàng)建一個 drawable
目錄。我在此目錄中放置一個 26 x 26 的圖標(biāo)文件(.png 格式),用于退出選項。
圖 7. 為 drawable 目錄添加一個圖標(biāo)
我的下一個步驟是在選項菜單中引用該圖標(biāo),具體做法是在我的 overheard_word.xml
文件中更新 menu
項,如下所示:
- android:icon="@drawable/quit_icon"
如果您嚴(yán)格遵循我的步驟,則應(yīng)更新同一元素的 id
。為它指定一個描述性的字符串值,如下所示:
- android:id="@+id/quit_item"
進行下一個步驟,即在 onOptionsItemSelected
方法內(nèi)部實現(xiàn)退出行為時,使用一個描述性的、易于理解的字符串值是很有幫助的。我們將能夠通過 quit_item
的 ID 在選擇事件中引用菜單項。現(xiàn)在啟動模擬器并按下 Menu 按鈕。我認為您會喜歡所看到的情景!
圖 8. 好圖標(biāo)!(由 Glyphish 提供)
實現(xiàn)菜單行為
現(xiàn)在我有一個外觀漂亮的圖標(biāo),可以用于 Quit 菜單項(我希望您也有一個圖標(biāo)用于自己的應(yīng)用程序),但我仍然需要添加代碼,從而告訴應(yīng)用程序當(dāng)按鈕被按下時應(yīng)該做什么。
實現(xiàn)選項菜單中的任意行為都要從重寫 onOptionsItemSelected
方法開始。因此重寫該方法,然后更新代碼,使其看起來像下面這樣(但記住要針對您自己的應(yīng)用程序調(diào)整菜單項 ID):
清單 3. 處理菜單項選擇
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.quit_item:
- this.finish();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
注意,這只是一條簡單的 switch
語句。如果選擇 quit_item
的 id
,將調(diào)用 finish
方法來關(guān)閉應(yīng)用程序。
在模擬器中試用這段新代碼:按 Menu 按鈕,選擇退出(X)選項,并觀察 LogCat 上出現(xiàn)的內(nèi)容。您應(yīng)該看到一個完整的 Activity
生命周期,依次分為如下幾個階段:onPause
、onStop
和 onDestroy
。
Android 3.x 中的操作欄
如前所述,較新版本的 Android(Honeycomb 及更高版本)使用操作欄取代了選項菜單。較新的設(shè)備甚至不一定有 Menu 按鈕,因此了解應(yīng)用程序的導(dǎo)航(或其他功能)也能用在操作欄中。
確保通過為選項菜單編碼而實現(xiàn)的導(dǎo)航功能也能用在操作欄中,并不需要做很多工作。您已經(jīng)實現(xiàn)了所有需要的方法,剩下的工作只是對 XML 源文件進行一些修改。
首先需要創(chuàng)建一個模擬器實例,用于模擬使用操作欄而非菜單按鈕的設(shè)備。最簡單的做法是模擬一臺平板電腦。在 Android SDK 安裝中啟動 Android SDK Manager 命令行應(yīng)用程序(是位于 tools
目錄中的 android
命令)。SDK Manager 啟動并運行后,從 Tools 菜單選擇 Manage AVDs... 選項。這將顯示一個對話框,在其中可以定義一個新的模擬器或 Android Virtual Device(或 AVD)。選擇 7.0'' WSVGA (Tablet) (1024 x 600: mdpi),然后將模擬器的目標(biāo)設(shè)定為至少 Android 4.2.2。完成后,您就有了一個不響應(yīng)菜單按鈕的模擬器,如 圖 9 中所示。
圖 9. 創(chuàng)建一個平板電腦模擬器
接 下來,在該平板電腦實例中啟動您的應(yīng)用程序。您應(yīng)該在右下角看到一條由三個點組成的垂直線。它看起來很棒,對嗎?默認情況下,Android 將保留菜單行為,甚至在較新的顯示設(shè)備中也是這樣。通過更新應(yīng)用程序的 XML 資源,您可以升級操作欄的外觀與行為,讓它變得更加自然。
從應(yīng)用程序的 AndroidManifest.xml
文件開始,您將在該文件中更新 SDK 目標(biāo):
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="17" />
接下來,在 Eclipse 中進入您項目的 Properties 頁面,并將 Project Build Target 更新為高于 Android 4.2.2 的任意 Android 版本。單擊 OK 并讓項目重新編譯。然后在 menu
目錄中找到菜單 XML 文件。更新它的內(nèi)容,如下所示,這將保留 Quit 的 item
定義。
- android:showAsAction="always"
最后,如果您的項目在 res
目錄下沒有兩個名為 values-v11
和 values-v14
的子目錄,那么創(chuàng)建它們。接下來,在 values-v11
目錄中添加以下 XML 文件:
- <resources>
- <style name="AppBaseTheme" parent="android:Theme.Holo.Light"></style>
- </resources>
在 values-v14
目錄中,添加此文件:
- <resources>
- <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"></style>
- </resources>
現(xiàn)在重啟模擬器,您的新圖標(biāo)應(yīng)該出現(xiàn)在右上角:
圖 10. 一個帶圖標(biāo)的操作欄
現(xiàn)在回到 menu
目錄中的菜單文件(其中定義了 quit
項),將 showAsAction
更改為 never
。重新運行您的應(yīng)用程序,應(yīng)該可以在右上角看到這三個垂直的點。
不要忘記重新設(shè)定
注意,如果希望將應(yīng)用程序目標(biāo)保持為 Gingerbread,您需要重新設(shè)定項目的編譯目標(biāo)并撤消本節(jié)內(nèi)容中對 XML 文件所做的更改。這些更改無法做到向后兼容!
圖標(biāo)的更多樂趣
迄今為止,您已經(jīng)為以 Gingerbread 為目標(biāo)的應(yīng)用程序添加了一個菜單選項,看到它被十分完美地轉(zhuǎn)換到實現(xiàn)操作欄的新設(shè)備上,并了解如何通過對應(yīng)用程序的 XML 文件進行一些更新來升級該功能(如果您選擇這樣做)。
現(xiàn)在,讓我們總結(jié)一下您學(xué)到的關(guān)于圖標(biāo)的內(nèi)容。您已經(jīng)完成了為應(yīng)用程序的導(dǎo)航菜單添加一個圖標(biāo)的主要工作,因此更新它的 main 圖標(biāo)應(yīng)該沒什么問題。對用戶而言,這個圖標(biāo)就代表著您的應(yīng)用程序,因此必須知道如何更新和定制它。
我將更新 Overheard Word 的圖標(biāo),您也可以對自己的應(yīng)用程序這樣做。再說一遍,在 Internet 上進行快速搜索可以找到大量的圖標(biāo)站點。在這些站點中,我發(fā)現(xiàn)了一個有趣的圖標(biāo)集合,其中有一個圖標(biāo)確實深受我的喜愛:
圖 11. 一個漂亮的新圖標(biāo)
回想一下,這個圖標(biāo)在不同的設(shè)備配置文件上呈現(xiàn)不同的效果。我希望確保用戶對 Overheard Word 產(chǎn)生良好的第一印象,因此讓圖標(biāo)分辨率適合我的目標(biāo)設(shè)備范圍是很有必要的。幸運的是,我知道一個真正好用的站點,可以幫我實現(xiàn)這個目標(biāo)。
Android Asset Studio是一個 Google Code 項目,擁有大量可為 Android 開發(fā)人員提供助力的實用工具。我使用頻率很高的一個工具是 Launcher Icons。我要做的就是單擊 Launcher Icons 鏈接,然后上傳我的圖標(biāo)。該實用工具會針對各種設(shè)備配置文件生成正確尺寸的圖標(biāo)文件,然后我可以 zip 文件的格式下載它。該文件包含四個目錄,每個目錄下都包含一個我上傳文件的特定分辨率與尺寸的版本。
圖 12. Launcher Icons 為 Android 制作尺寸正確的圖標(biāo)
接下來,我將每個目錄中的 ic_launcher.png
文件復(fù)制到我應(yīng)用程序的 res
文件夾的相同子目錄中。注意,在此過程中,我可能會替換 Eclipse 生成的原始圖標(biāo)文件。
最后,我再次運行應(yīng)用程序,并等它出現(xiàn)在我的模擬器實例中。我單擊 Home 按鈕,然后查看結(jié)果:一個漂亮的應(yīng)用程序圖標(biāo)(對我而言)標(biāo)志著 OverHeard Word 是所有用戶設(shè)備上最有趣的應(yīng)用程序!
圖 13. 現(xiàn)在變得很形象!
結(jié)束語
在本文中,您了解了 Activity
的生命周期,并知道如何使用它來改進應(yīng)用程序?qū)υO(shè)備資源的利用。您還學(xué)會了如何使用菜單和操作欄定義與實現(xiàn)導(dǎo)航構(gòu)件,以及如何使用圖標(biāo)替換單詞按鈕。
您 在本文中學(xué)到的所有內(nèi)容對于構(gòu)建 Android 應(yīng)用程序都是至關(guān)重要的。Android 上的移動開發(fā)很容易上手,當(dāng)然也樂趣無窮,但我希望您也要明白它與您所熟悉的 Java 開發(fā)屬于不同范式。Google Play 與其他應(yīng)用程序商店中存在著成千上萬個應(yīng)用程序,因此通常只有規(guī)劃良好、設(shè)計用心和編碼精妙的應(yīng)用程序才能名列前茅。要學(xué)的地方還有很多!