簡介:
Activity是一個應用組件,用戶可與其提供的屏幕進行交互,以執行撥打電話、拍攝照片、發送電子郵件等操作。每個Activity都會獲得一個用于繪制其用戶界面的窗口。窗口通常會充滿屏幕,但也可小于屏幕并浮動子其他窗口之上。
一個應用通常由多個彼此松散聯系的Activity組成。一般會指定應用中的某個Activity為“主”Activity,即應用首次啟動時呈現給用戶的那個Activity。而且每個Activity均可啟動另外的Activity,以便執行不同的操作。每次新的Activity啟動時,前一Activity便會停止,但系統會在堆棧(“返回?!保┲斜A粼揂ctivity。當新的Activity啟動時,系統會將其推送到返回棧中,并獲得用戶焦點。返回棧,遵循“后進先出”的機制,因此當用戶完成當前Activity并按下返回按鈕時,系統會從堆棧中將其彈出(并銷毀),恢復前一Activity。
當一個Activity因某一個新的Activity啟動而停止時,系統通過該Activity的聲明周期回調方法通知其這一狀態變化。Activity因狀態變化-系統是創建Activity、停止Activity、恢復Activity還是銷毀Activity-收到的回調方法可能有若干種,每一種回調方法都會為你提供執行與該狀態變化相應的特定操作的機會。
創建 Activity
要創建 Activity,您必須創建Activity的子類(或使用其現有子類)。您需要在子類中實現 Activity 在其生命周期的各種狀態之間轉變時(例如創建 Activity、停止 Activity、恢復 Activity 或銷毀 Activity 時)系統調用的回調方法。 兩個最重要的回調方法是:
您必須實現此方法。系統會在創建您的 Activity 時調用此方法。您應該在實現內初始化 Activity 的必需組件。 最重要的是,您必須在此方法內調用setContentView(),以定義 Activity 用戶界面的布局。
系統將此方法作為用戶離開 Activity 的第一個信號(但并不總是意味著 Activity 會被銷毀)進行調用。 您通常應該在此方法內確認在當前用戶會話結束后仍然有效的任何更改(因為用戶可能不會返回)。
您還應使用幾種其他生命周期回調方法,以便提供流暢的 Activity 間用戶體驗,以及處理導致您的 Activity 停止甚至被銷毀的意外中斷。 后文的管理 Activity 生命周期部分對所有生命周期回調方法進行了闡述。
實現用戶界面
Activity 的用戶界面是由層級式視圖—衍生自View類的對象—提供的。每個視圖都控制 Activity 窗口內的特定矩形空間,可對用戶交互作出響應。 例如,視圖可以是在用戶觸摸時啟動某項操作的按鈕。
您可以利用 Android 提供的許多現成視圖設計和組織您的布局?!靶」ぞ摺笔翘峁┌粹o、文本字段、復選框或僅僅是一幅圖像等屏幕視覺(交互式)元素的視圖。 “布局”是衍生自ViewGroup的視圖,為其子視圖提供唯一布局模型,例如線性布局、網格布局或相對布局。您還可以為View類和ViewGroup類創建子類(或使用其現有子類)來自行創建小工具和布局,然后將它們應用于您的 Activity 布局。
利用視圖定義布局的最常見方法是借助保存在您的應用資源內的 XML 布局文件。這樣一來,您就可以將用戶界面的設計與定義 Activity 行為的源代碼分開維護。 您可以通過setContentView()將布局設置為 Activity 的 UI,從而傳遞布局的資源 ID。不過,您也可以在 Activity 代碼中創建新View,并通過將新View插入ViewGroup來創建視圖層次,然后通過將根ViewGroup傳遞到setContentView()來使用該布局。
如需了解有關創建用戶界面的信息,請參閱用戶界面文檔。
在清單文件中聲明 Activity
您必須在清單文件中聲明您的 Activity,這樣系統才能訪問它。 要聲明您的 Activity,請打開您的清單文件,并將<activity>元素添加為<application>元素的子項。例如:
...
...
您還可以在此元素中加入幾個其他特性,以定義 Activity 標簽、Activity 圖標或風格主題等用于設置 Activity UI 風格的屬性。android:name特性是唯一的必需特性—它指定 Activity 的類名。應用一旦發布,即不應更改此類名,否則,可能會破壞諸如應用快捷方式等一些功能(請閱讀博客文章Things That Cannot Change[不能更改的內容])。
在清單文件中聲明 Activity
您必須在清單文件中聲明您的 Activity,這樣系統才能訪問它。 要聲明您的 Activity,請打開您的清單文件,并將<activity>元素添加為<application>元素的子項。例如:
...
...
使用 Intent 過濾器
<activity>元素還可指定各種 Intent 過濾器—使用<Intent-filter>元素—以聲明其他應用組件激活它的方法。
當您使用 Android SDK 工具創建新應用時,系統自動為您創建的存根 Activity 包含一個 Intent 過濾器,其中聲明了該 Activity 響應“主”操作且應置于“launcher”類別內。 Intent 過濾器的內容與以下所示類似:
<action>元素指定這是應用的“主”入口點。<category>元素指定此 Activity 應列入系統的應用啟動器內(以便用戶啟動該 Activity)。
如果您打算讓應用成為獨立應用,不允許其他應用激活其 Activity,則您不需要任何其他 Intent 過濾器。 正如前例所示,只應有一個 Activity 具有“主”操作和“launcher”類別。 您不想提供給其他應用的 Activity 不應有任何 Intent 過濾器,您可以利用顯式 Intent 自行啟動它們
啟動 Activity
您可以通過調用startActivity(),并將其傳遞給描述您想啟動的 Activity 的Intent來啟動另一個 Activity。Intent 對象會指定您想啟動的具體 Activity 或描述您想執行的操作類型(系統會為您選擇合適的 Activity,甚至是來自其他應用的 Activity)。 Intent 對象還可能攜帶少量供所啟動 Activity 使用的數據。
在您的自有應用內工作時,您經常只需要啟動某個已知 Activity。 您可以通過使用類名創建一個顯式定義您想啟動的 Activity 的 Intent 對象來實現此目的。 例如,可以通過以下代碼讓一個 Activity 啟動另一個名為SignInActivity的 Activity:
Intentintent=newIntent(this,SignInActivity.class);
startActivity(intent);
不過,您的應用可能還需要利用您的 Activity 數據執行某項操作,例如發送電子郵件、短信或狀態更新。 在這種情況下,您的應用自身可能不具有執行此類操作所需的 Activity,因此您可以改為利用設備上其他應用提供的 Activity 為您執行這些操作。 這便是 Intent 對象的真正價值所在—您可以創建一個 Intent 對象,對您想執行的操作進行描述,系統會從其他應用啟動相應的 Activity。 如果有多個 Activity 可以處理 Intent,則用戶可以選擇要使用哪一個。 例如,如果您想允許用戶發送電子郵件,可以創建以下 Intent 對象:
Intentintent=newIntent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL,recipientArray);
startActivity(intent);
添加到 Intent 中的EXTRA_EMAILextra 是一個字符串數組,其中包含應將電子郵件發送到的電子郵件地址。 當電子郵件應用響應此 Intent 時,它會讀取 extra 中提供的字符串數組,并將它們放入電子郵件撰寫窗體的“收件人”字段。 在這種情況下,電子郵件應用的 Activity 啟動,并且當用戶完成操作時,您的 Activity 會恢復執行。
結束 Activity
您可以通過調用 Activity 的finish()方法來結束該 Activity。您還可以通過調用finishActivity()結束您之前啟動的另一個 Activity。
注:在大多數情況下,您不應使用這些方法顯式結束 Activity。 正如下文有關 Activity 生命周期的部分所述,Android 系統會為您管理 Activity 的生命周期,因此您無需完成自己的 Activity。 調用這些方法可能對預期的用戶體驗產生不良影響,因此只應在您確實不想讓用戶返回此 Activity 實例時使用。
管理 Activity 生命周期
通過實現回調方法管理 Activity 的生命周期對開發強大而又靈活的應用至關重要。 Activity 的生命周期會直接受到 Activity 與其他 Activity、其任務及返回棧的關聯性的影響。
Activity 基本上以三種狀態存在:
已繼續
此 Activity 位于屏幕前臺并具有用戶焦點。(有時也將此狀態稱作“運行中”。)
已暫停
另一個 Activity 位于屏幕前臺并具有用戶焦點,但此 Activity 仍可見。也就是說,另一個 Activity 顯示在此 Activity 上方,并且該 Activity 部分透明或未覆蓋整個屏幕。 已暫停的 Activity 處于完全 Activity 狀態(Activity對象保留在內存中,它保留了所有狀態和成員信息,并與窗口管理器保持連接),但在內存極度不足的情況下,可能會被系統終止。
已停止
該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位于“后臺”)。 已停止的 Activity 同樣仍處于 Activity 狀態(Activity對象保留在內存中,它保留了所有狀態和成員信息,但未與窗口管理器連接)。 不過,它對用戶不再可見,在他處需要內存時可能會被系統終止。
如果 Activity 處于暫?;蛲V範顟B,系統可通過要求其結束(調用其finish()方法)或直接終止其進程,將其從內存中刪除。(將其結束或終止后)再次打開 Activity 時,必須重建。
圖 1 說明了這些循環以及 Activity 在狀態轉變期間可能經過的路徑。矩形表示回調方法,當 Activity 在不同狀態之間轉變時,您可以實現這些方法來執行操作。
管理 Activity 生命周期的引言部分簡要提及,當 Activity 暫?;蛲V箷r,Activity 的狀態會得到保留。 確實如此,因為當 Activity 暫?;蛲V箷r,Activity對象仍保留在內存中 — 有關其成員和當前狀態的所有信息仍處于 Activity 狀態。 因此,用戶在 Activity 內所做的任何更改都會得到保留,這樣一來,當 Activity 返回前臺(當它“繼續”)時,這些更改仍然存在。
不過,當系統為了恢復內存而銷毀某項 Activity 時,Activity對象也會被銷毀,因此系統在繼續 Activity 時根本無法讓其狀態保持完好,而是必須在用戶返回Activity時重建Activity對象。但用戶并不知道系統銷毀 Activity 后又對其進行了重建,因此他們很可能認為 Activity 狀態毫無變化。 在這種情況下,您可以實現另一個回調方法對有關 Activity 狀態的信息進行保存,以確保有關 Activity 狀態的重要信息得到保留:onSaveInstanceState()。
系統會先調用onSaveInstanceState(),然后再使 Activity 變得易于銷毀。系統會向該方法傳遞一個Bundle,您可以在其中使用putString()和putInt()等方法以名稱-值對形式保存有關 Activity 狀態的信息。然后,如果系統終止您的應用進程,并且用戶返回您的 Activity,則系統會重建該 Activity,并將Bundle同時傳遞給onCreate()和onRestoreInstanceState()。您可以使用上述任一方法從Bundle提取您保存的狀態并恢復該 Activity 狀態。如果沒有狀態信息需要恢復,則傳遞給您的Bundle是空值(如果是首次創建該 Activity,就會出現這種情況)。
圖 2.在兩種情況下,Activity 重獲用戶焦點時可保持狀態完好:系統在銷毀 Activity 后重建 Activity,Activity 必須恢復之前保存的狀態;系統停止 Activity 后繼續執行 Activity,并且 Activity 狀態保持完好。
注:無法保證系統會在銷毀您的 Activity 前調用onSaveInstanceState(),因為存在不需要保存狀態的情況(例如用戶使用“返回”按鈕離開您的 Activity 時,因為用戶的行為是在顯式關閉 Activity)。 如果系統調用onSaveInstanceState(),它會在調用onStop()之前,并且可能會在調用onPause()之前進行調用。
不過,即使您什么都不做,也不實現onSaveInstanceState(),Activity類的onSaveInstanceState()默認實現也會恢復部分 Activity 狀態。具體地講,默認實現會為布局中的每個View調用相應的onSaveInstanceState()方法,讓每個視圖都能提供有關自身的應保存信息。Android 框架中幾乎每個小工具都會根據需要實現此方法,以便在重建 Activity 時自動保存和恢復對 UI 所做的任何可見更改。例如,EditText小工具保存用戶輸入的任何文本,CheckBox小工具保存復選框的選中或未選中狀態。您只需為想要保存其狀態的每個小工具提供一個唯一的 ID(通過android:id屬性)。如果小工具沒有 ID,則系統無法保存其狀態。