詳解 Android 的 Activity 元件【Z】
詳解 Android 的 Activity 元件
和 J2ME 的 MIDlet 一樣,在 android 中,Activity 的生命週期交給系統統一管理。與 MIDlet 不同的是安裝在 android 中的所有的 Activity 都是平等的。
在 android 中,Activity 擁有四種基本狀態:
- Active/Runing 一個新 Activity 啟動入棧後,它在螢幕最前端,處於棧的最頂端,此時它處於可見並可和使用者互動的啟用狀態。
- Paused 當 Activity 被另一個透明或者 Dialog 樣式的 Activity 覆蓋時的狀態。此時它依然與視窗管理器保持連線,系統繼續維護其內部狀態,所以它仍然可見,但它已經失去了焦點故不可與使用者互動。
- Stoped 當 Activity 被另外一個 Activity 覆蓋、失去焦點並不可見時處於 Stop ed 狀態。
- Killed Activity 被系統殺死回收或者沒有被啟動時處於 Killed 狀態。
當一個 Activity 例項被建立、銷燬或者啟動另外一個 Activity 時,它在這四種狀態之間進行轉換,這種轉換的發生依賴於使用者程式的動作。下圖說明了 Activity 在不同狀態間轉換的時機和條件:
如上所示,Android 程式設計師可以決定一個 Activity 的“生”,但不能決定它的“死”,也就時說程式設計師可以啟動一個 Activity,但是卻不能手動的“結束”一個 Activity。當你呼叫 Activity.finish() 方 法時,結果和使用者按下 BACK 鍵一樣:告訴 Activity Manager 該 Activity 例項完成了相應的工作,可以被“回收”。隨後 Activity Manager 啟用處於棧第二層的 Activity 並重新入棧,同時原 Activity 被壓入到棧的第二層,從 Active 狀態轉到 Paused 狀態。例如:從 Activity1 中啟動了 Activity2,則當前處於棧頂端的是 Activity2,第二層是 Activity1,當我們呼叫 Activity2.finish() 方法時,Activity Manager 重新啟用 Activity1 併入棧,Activity2 從 Active 狀態轉換 Stoped 狀態,Activity1. onActivityResult(int requestCode, int resultCode, Intent data) 方法被執行,Activity2 返回的資料通過 data 引數返回給 Activity1。
Android 是通過一種 Activity 棧的方式來管理 Activity 的,一個 Activity 的例項的狀態決定它在棧中的位置。處於前臺的 Activity 總是在棧的頂端,當前臺的 Activity 因為異常或其它原因被銷燬時,處於棧第二層的 Activity 將被啟用,上浮到棧頂。當新的 Activity 啟動入棧時,原 Activity 會被壓入到棧的第二層。一個 Activity 在棧中的位置變化反映了它在不同狀態間的轉換。Activity 的狀態與它在棧中的位置關係如下圖所示:
如上所示,除了最頂層即處在 Active 狀態的 Activity 外,其它的 Activity 都有可能在系統記憶體不足時被回收,一個 Activity 的例項越是處在棧的底層,它被系統回收的可能性越大。系統負責管理棧中 Activity 的例項,它根據 Activity 所處的狀態來改變其在棧中的位置。
在 android.app.Activity 類中,Android 定義了一系列與生命週期相關的方法,在我們自己的 Activity 中,只是根據需要複寫需要的方法,Java 的多型性會保證我們自己的方法被虛擬機器呼叫,這一點與 J2ME 中的 MIDlet 類似。
public class OurActivity extends Activity { protected void onCreate(Bundle savedInstanceState); protected void onStart(); protected void onResume(); protected void onPause(); protected void onStop(); protected void onDestroy(); } |
這些方法的說明如下:
-
-
- protected void onCreate(Bundle savedInstanceState) 一個 Activity 的例項被啟動時呼叫的第一個方法。一般情況下,我們都覆蓋該方法作為應用程式的一個入口點,在這裡做一些初始化資料、設定使用者介面等工作。大多數情況下,我們都要在這裡從 xml 中載入設計好的使用者介面。例如:
-
setContentView(R.layout.main); |
當然,也可從 savedInstanceState 中讀我們儲存到儲存裝置中的資料,但是需要判斷 savedInstanceState 是否為 null ,因為 Activity 第一次啟動時並沒有資料被存貯在裝置中:
if(savedInstanceState!=null){ savedInstanceState.get("Key"); } |
-
-
- protected void onStart() 該方法在 onCreate() 方法之後被呼叫,或者在 Activity 從 Stop 狀態轉換為 Active 狀態時被呼叫。
- protected void onResume() 在 Activity 從 Pause 狀態轉換到 Active 狀態時被呼叫。
- protected void onResume() 在 Activity 從 Active 狀態轉換到 Pause 狀態時被呼叫。
- protected void onStop() 在 Activity 從 Active 狀態轉換到 Stop 狀態時被呼叫。一般我們在這裡儲存 Activity 的狀態資訊。
- protected void onDestroy() 在 Active 被結束時呼叫,它是被結束時呼叫的最後一個方法,在這裡一般做些釋放資源,清理記憶體等工作。
-
此外,Android 還定義了一些不常用的與生命週期相關的方法可用:
protected void onPostCreate(Bundle savedInstanceState); protected void onRestart(); protected void onPostResume(); |
Android 提供的文件詳細的說明了它們的呼叫規則。
在 android 中建立一個 Activity 是很簡單的事情,編寫一個繼承自 android.app.Activity 的 Java 類並在 AndroidManifest.xml 宣告即可。下面是一個為了研究 Activity 生命週期的一個 Activity 例項(工程原始碼見下載):
Activity 檔案:
public class EX01 extends Activity { private static final String LOG_TAG = EX01.class.getSimpleName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.e(LOG_TAG, "onCreate"); } @Override protected void onStart() { Log.e(LOG_TAG, "onStart"); super.onStart(); } @Override protected void onResume() { Log.e(LOG_TAG, "onResume"); super.onResume(); } @Override protected void onPause() { Log.e(LOG_TAG, "onPause"); super.onPause(); } @Override protected void onStop() { Log.e(LOG_TAG, "onStop"); super.onStop(); } @Override protected void onDestroy() { Log.e(LOG_TAG, "onDestroy "); super.onDestroy(); } } |
AndroidManifest.xml 中通過 <activity> 節點說明 Activity,將 apk 檔案安裝後,系統根據這裡的說明來查詢讀取 Activity,本例中的說明如下:
<activity android:name=".EX01" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> |
Activity.startActivity() 方法可以根據傳入的引數啟動另外一個 Activity:
Intent intent =new Intent(CurrentActivity.this,OtherActivity.class); startActivity(intent); |
當然,OtherActivity 同樣需要在 AndroidManifest.xml 中定義。
在 Android 中,不同的 Activity 例項可能執行在一個程式中,也可能執行在不同的程式中。因此我們需要一種特別的機制幫助我們在 Activity 之間傳遞訊息。Android 中通過 Intent 物件來表示一條訊息,一個 Intent 物件不僅包含有這個訊息的目的地,還可以包含訊息的內容,這好比一封 Email,其中不僅應該包含收件地址,還可以包含具體的內容。對於一個 Intent 物件,訊息“目的地”是必須的,而內容則是可選項。
在上面的例項中通過 Activity. startActivity(intent) 啟動另外一個 Activity 的時候,我們在 Intent 類的構造器中指定了“收件人地址”。
如果我們想要給“收件人”Activity 說點什麼的話,那麼可以通過下面這封“e-mail”來將我們訊息傳遞出去:
Intent intent =new Intent(CurrentActivity.this,OtherActivity.class); // 建立一個帶“收件人地址”的 email Bundle bundle =new Bundle();// 建立 email 內容 bundle.putBoolean("boolean_key", true);// 編寫內容 bundle.putString("string_key", "string_value"); intent.putExtra("key", bundle);// 封裝 email startActivity(intent);// 啟動新的 Activity |
那麼“收件人”該如何收信呢?在 OtherActivity 類的 onCreate() 或者其它任何地方使用下面的程式碼就可以開啟這封“e-mail”閱讀其中的資訊:
Intent intent =getIntent();// 收取 email Bundle bundle =intent.getBundleExtra("key");// 開啟 email bundle.getBoolean("boolean_key");// 讀取內容 bundle.getString("string_key"); |
上面我們通過 bundle 物件來傳遞資訊,bundle 維護了一個 HashMap<String, Object> 物件,將我們的資料存貯在這個 HashMap 中來進行傳遞。但是像上面這樣的程式碼稍顯複雜,因為 Intent 內部為我們準備好了一個 bundle ,所以我們也可以使用這種更為簡便的方法:
Intent intent =new Intent(EX06.this,OtherActivity.class); intent.putExtra("boolean_key", true); intent.putExtra("string_key", "string_value"); startActivity(intent); |
接收:
Intent intent=getIntent(); intent.getBooleanExtra("boolean_key",false); intent.getStringExtra("string_key"); |
SharedPreferences 使用 xml 格式為 Android 應用提供一種永久的資料存貯方式。對於一個 Android 應用,它存貯在檔案系統的 /data/ data/your_app_package_name/shared_prefs/ 目錄下,可以被處在同一個應用中的所有 Activity 訪問。Android 提供了相關的 API 來處理這些資料而不需要程式設計師直接操作這些檔案或者考慮資料同步問題。
// 寫入 SharedPreferences SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE); Editor editor = preferences.edit(); editor.putBoolean("boolean_key", true); editor.putString("string_key", "string_value"); editor.commit(); // 讀取 SharedPreferences SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE); preferences.getBoolean("boolean_key", false); preferences.getString("string_key", "default_value"); |
Android 提供了包括 SharedPreferences 在內的很多種資料存貯方式,比如 SQLite,檔案等,程式設計師可以通過這些 API 實現 Activity 之間的資料交換。如果必要,我們還可以使用 IPC 方式。
Intent Filter 描述了一個元件願意接收什麼樣的 Intent 物件,Android 將其抽象為 android.content.IntentFilter 類。在 Android 的 AndroidManifest.xml 配置檔案中可以通過 <intent-filter > 節點為一個 Activity 指定其 Intent Filter,以便告訴系統該 Activity 可以響應什麼型別的 Intent。
當程式設計師使用 startActivity(intent) 來啟動另外一個 Activity 時,如果直接指定 intent 了物件的 Component 屬性,那麼 Activity Manager 將試圖啟動其 Component 屬性指定的 Activity。否則 Android 將通過 Intent 的其它屬性從安裝在系統中的所有 Activity 中查詢與之最匹配的一個啟動,如果沒有找到合適的 Activity,應用程式會得到一個系統丟擲的異常。這個匹配的過程如下:
圖 4. Activity 種 Intent Filter 的匹配過程
Action 是一個使用者定義的字串,用於描述一個 Android 應用程式元件,一個 Intent Filter 可以包含多個 Action。在 AndroidManifest.xml 的 Activity 定義時可以在其 <intent-filter > 節點指定一個 Action 列表用於標示 Activity 所能接受的“動作”,例如:
<intent-filter > <action android:name="android.intent.action.MAIN" /> <action android:name="com.zy.myaction" /> …… </intent-filter> |
如果我們在啟動一個 Activity 時使用這樣的 Intent 物件:
Intent intent =new Intent(); intent.setAction("com.zy.myaction"); |
那麼所有的 Action 列表中包含了“com.zy.myaction ”的 Activity 都將會匹配成功。
Android 預定義了一系列的 Action 分別表示特定的系統動作。這些 Action 通過常量的方式定義在 android.content. Intent 中,以“ACTION_ ”開頭。我們可以在 Android 提供的文件中找到它們的詳細說明。
一個 Intent 可以通過 URI 攜帶外部資料給目標元件。在 <intent-filter > 節點中,通過 <data/> 節點匹配外部資料。
mimeType 屬性指定攜帶外部資料的資料型別,scheme 指定協議,host、port、path 指定資料的位置、埠、和路徑。如下:
<data android:mimeType="mimeType" android:scheme="scheme" android:host="host" android:port="port" android:path="path"/> |
如果在 Intent Filter 中指定了這些屬性,那麼只有所有的屬性都匹配成功時 URI 資料匹配才會成功。
<intent-filter > 節點中可以為元件定義一個 Category 類別列表,當 Intent 中包含這個列表的所有專案時 Category 類別匹配才會成功。
Android 內建了方向感應器的支援。在 G1 中,Android 會根據 G1 所處的方向自動在豎屏和橫屏間切換。但是有時我們的應用程式僅能在橫屏 / 豎屏時執行,比如某些遊戲,此時我們需要鎖定該 Activity 執行時的螢幕方向,<activity > 節點的 android:screenOrientation 屬性可以完成該項任務,示例程式碼如下:
<activity android:name=".EX01" android:label="@string/app_name" android:screenOrientation="portrait">// 豎屏 , 值為 landscape 時為橫屏 ………… </activity> |
要使一個 Activity 全屏執行,可以在其 onCreate() 方法中新增如下程式碼實現:
// 設定全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 去除標題欄 requestWindowFeature(Window.FEATURE_NO_TITLE); |
為了更友好的使用者體驗,在處理一些需要花費較長時間的任務時可以使用一個進度條來提示使用者“不要著急,我們正在努力的完成你交給的任務”。如下圖:
在 Activity 的標題欄中顯示進度條不失為一個好辦法,下面是實現程式碼:
// 不明確進度條 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.main); setProgressBarIndeterminateVisibility(true); // 明確進度條 requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.main); setProgress(5000);
相關文章
- 詳解Android中的四大元件之一:Activity詳解Android元件
- Android Activity生命週期詳解Android
- [Android]Android Activity 啟動模式詳解Android模式
- Android中Activity的LunchMode引數詳解Android
- Android 元件系列-----Activity初步Android元件
- android Fragments詳解五:與activity通訊AndroidFragment
- Android Activity的四大啟動模式詳解Android模式
- Android元件詳解—TextViewAndroid元件TextView
- Android四大元件——Activity——Activity的生命週期Android元件
- Android Activity的生命週期和啟動模式詳解Android模式
- android Activity的啟動模式 作用簡析+demo詳解Android模式
- 解開Android應用程式元件Activity的"singleTask"之謎(3)Android元件
- Android 元件系列-----Activity生命週期Android元件
- Activity的啟動模式詳解模式
- Android架構元件WorkManager詳解Android架構元件
- Android 四大元件之 ActivityAndroid元件
- Android四大元件之ActivityAndroid元件
- Android 四大元件之 " Activity "Android元件
- Android 元件系列-----Activity儲存狀態Android元件
- Android基本控制元件和Activity的基本應用Android控制元件
- Android 元件系列-----Activity的傳值和回傳值Android元件
- Android四大元件之Activity篇Android元件
- Android之Activity啟動流程詳解(基於api28)AndroidAPI
- Activity的Launch mode詳解 singleTask正解
- BCDEDIT命令詳解 【Z】
- Android Jetpack元件之Lifecycles庫詳解AndroidJetpack元件
- Android應用開發—Intent元件詳解AndroidIntent元件
- Android的基本控制元件和Activity的應用總結Android控制元件
- android Fragment與Activity互動,互相發資料(附圖詳解)AndroidFragment
- 【Android】安卓四大元件之Activity(二)Android安卓元件
- Android面試常客--四大元件之ActivityAndroid面試元件
- Android必知必會的四大元件 -- Activity篇Android元件
- 重溫Android四大元件—Activity的生命週期Android元件
- Android生命週期元件Lifecycle使用詳解Android元件
- Android控制元件之ConstraintLayout詳解Android控制元件AI
- Android 控制元件架構與自定義控制元件詳解Android控制元件架構
- Activity的生命週期和啟動模式詳解模式
- OpenStack的Swift元件詳解Swift元件