完全看懂 Android 四大元件之 Activity(上)
一、概述
簡單來講,Activity 就是一個視覺化介面,負責承建一個螢幕視窗,防止 UI 元件,供使用者互動。一般來說承建 Activity 有三個步驟:
- 承建 Activity 類;
- 在 AndroidManifest.xml 中註冊;
- 設定佈局檔案(可選)。
二、Activity 的啟動方法
2.1、顯示啟動
明確指定要啟動的 Activity 的 c l a s s \color{red}{class} class 或者 包 名 . a c t i v i t y 類 名 \color{red}{包名.activity類名} 包名.activity類名,顯示啟動主要有三種方式:
- 方式一:class 跳轉(最常用)
Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent);
- 方式二:包名.類名 跳轉
Intent intent = new Intent(); intent.setClassName(MainActivity.this, "com.zjgsu.activitydemo.SecondActivity"); startActivity(intent);
- 方式三:ComponentName 跳轉
Intent intent = new Intent(); intent.setComponent(new ComponentName(MainActivity.this, SecondActivity.class)); startActivity(intent);
2.2、隱式啟動
設定啟動過濾器,通過指定的 a c t i o n \color{red}{action} action 或 a c t i o n 和 d a t a \color{red}{action 和 data} action和data 屬性,系統會查詢符合條件的 Activity,並啟動它,隱私啟動主要有兩種方式:
- 方式一:傳入 actionName
Intent intent = new Intent("abcd.SecondActivity"); startActivity(intent);
- 方式二:設定 action
Intent intent = new Intent(); intent.setAction("abcd.SecondActivity"); startActivity(intent);
注意:如果自己定義的某個 Activity 要通過隱式啟動,在 AndroidManifest.xml 中必須加上 android.intent.category.DEFAULT,否則不起作用。
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="abcd.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
2.2.1、隱式啟動如果兩個 activity 的 actionName是一樣的會怎樣呢?
如下所示,我建立了兩個 Activity,然後這兩個 Activity 的 actionName 我設定成一樣的,然後我通過隱式啟動 Activity,會怎樣呢?
<activity android:name=".SecondActivity"
android:label="第二個介面">
<intent-filter>
<action android:name="abcd.SecondActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ThirdActivity"
android:label="第三個介面">
<intent-filter>
<action android:name="abcd.SecondActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
執行效果如下所示:
看上面的 gif 動圖我們就可以看出來,這種情況下 Android 會讓我們選擇要執行的 Activity。即當有多個 Action 匹配隱式匹配的條件時,將會彈出選擇框供使用者選擇。
三、Activity 的生命週期
我們就以下面這張 Activity 生命週期圖為例子吧:
一個 Activity 啟動的時候會依次呼叫 onCreate() --> onStart() --> onResume() --> onPause() --> onStop() --> onDestroy()。當執行到 onResume() 的時候這個 Activity 就變成了可操作狀態。
3.1、單 Activity 生命週期的呼叫順序
- onCreate() 建立 Activity 時呼叫
- onStart() 當 Activity 介面變為使用者可見時呼叫
- onResume() 當 Activity 介面獲取到焦點時呼叫(介面按鈕可點選,文字框可輸入等)
- onPause() 當 Activity 介面失去焦點時呼叫(介面按鈕不可點選,文字框不可輸入等)
- onStop() 當 Activity 介面變為使用者不可見時呼叫
- onDestroy() 當 Activity 被銷燬時呼叫
- onRestart() 當 Activity 再次啟動時呼叫
3.2、多 Activity 生命週期的呼叫順序
多Activity的生命週期如下圖所示:
上面那張圖的操作流程:開啟 A activity,點選按鈕啟動 B activity,在 B activity 中點選返回鍵。程式碼執行截圖如下:
四、Activity 的啟動模式
Activity 的啟動模式決定了新生產的 Activity 例項是否重用已存在的 Activity 例項,是否和其他 Activity 例項共用一個 Task。Task 是一個具有棧結構的物件,一個 Task 可以管理多個 Activity,啟動一個應用,也就建立一個與之對應的 Task。
4.1、四種啟動模式
- standard
預設的啟動模式,每次啟用 Activity 時(startActivity),都建立 Activity 例項,並放入任務棧; - singleTop
每次啟用 Activity 時,判斷該 Activity 例項是不是在棧頂,如果是,不需要建立,否則需要建立 Activity 例項; - singleTask
如果要啟用的那個 Activity 在任務棧中已經存在了,則不需要建立,只需要把此 Activity 以上的 Activity 例項都出棧,這個時候此 Activity 就到棧頂了,若不存在,就建立 Activity 例項; - singleInstance
只有一個例項,並且這個例項獨立執行在一個 Task 中,這個 Task 只有這個例項,不允許有別的 Activity 例項存在。
4.2、四種啟動模式程式碼演示
4.2.1、standard
我們先來看下效果:
可以看到,在 SecondActivity 裡面再次啟動 SecondActivity,standard 模式下的啟動方式會再次建立 SecondActivity 例項。使得任務棧中包含了兩個 SecondActivity 例項,所以我們點選返回鍵只是返回了上一個 SecondActivity,再次按返回鍵才回到 MainActivity。
主要程式碼如下所示:
// 啟動模式是 standard,不填預設就是 standard
<activity android:name=".SecondActivity"
android:launchMode="standard"/>
// SecondActivity
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.btn_start_self).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(SecondActivity.this, SecondActivity.class));
}
});
}
}
4.2.2、singleTop
我們還是用上面的例子來演示,只是把 SecondActivity 的啟動模式改成 singleTop,我們來看下效果:
可以看到,這個時候在 SecondActivity 裡面再次啟動自己,是不會建立 SecondActivity 例項的,應該這個時候 SecondActivity已經在棧頂了,而 singleTop 啟動模式會判斷該 Activity 例項是不是在棧頂,如果是,不需要建立,否則才建立 Activity 例項。
主要程式碼如下所示:
<activity android:name=".SecondActivity"
android:launchMode="singleTop"/>
問題1:如果這時候我們再建立一個 ThirdActivity,在 MainActivity 啟動 SecondActivity,再在 SecondActivity 裡面啟動 ThirdActivity,然後在 ThirdActivity 裡面啟動 SecondActivity,這時候任務棧中 Activity 的例項順序是怎樣的?
答:任務棧中自底向上的 Activity 例項順序為 MainActivity–>SecondActivity–>ThirdActivity–>SecondActivity。
4.2.3、singleTask
我們用上面的問題的例子來演示,只是把 SecondActivity 的啟動模式改成 singleTask,我們來看下效果:
這個時候任務棧中自底向上的 Activity 例項順序為 MainActivity–>SecondActivity。因為 SingleTask 啟動模式如果棧中存在 Activity 例項會把該 Activity 以上的所有 Activity 例項全部出棧。
主要程式碼如下所示:
<activity android:name=".SecondActivity"
android:launchMode="singleTask"/>
4.2.4、singleInstance
singleInstance 啟動模式和 singleTask 啟動模式有點像,都會保證任務棧中只有同一個 Activity 的例項,但是 singleInstance 會建立一個新的 Task。要想演示 singleInstance,我們需要把每個 Activity 所在的棧的 ID 列印出來。例子同上,只是修改啟動模式為 singleInstance。
列印日誌如下所示:
我們看到 SecondActivity 所在任務棧的 TaskId 是592,而 MainActivity 和 ThirdActivity 所在任務棧的 TaskId 是 591。這就說明 SecondActivity 執行在一個獨立的任務棧裡面,這個任務棧裡面只有 SecondActivity 這一個 Activity 例項。列印 TaskId 的方法如下:
Log.e("activityDemo2TAG", "ThirdActivity所在的task的id為:" + getTaskId());
五、利用 IntentFlag 設定 Activity 的啟動方式
講解這個知識點之前我們先來看一下 Task 和 taskAffinity 這兩個概念、
5.1、Task 基本概念
- Task 是一個具有棧結構的容器,可以放置多個 Activity 例項;
- 啟動一個應用,系統會為之建立一個 Task,來放置根 Activity;
- 一個 Activity 啟動另一個 Activity 時,預設情況下兩個 Activity 是放置在同一個 Task 中的,後者被壓入前者所在的 Task 棧,當使用者按下返回鍵,後者從 Task 中被彈出,前者又顯示在棧頂。
5.2、taskAffinity 基本概念
- 定義了 Activity 例項想要進入的 Task;
- 如果一個 Activity 沒有顯示的指明該 Activity 的 taskAffinity 屬性,那麼它的這個屬性就等於 Application 所指明的 taskAffinity,如果 Application 也沒有指明,那麼該 taskAffinity 的值就等於包名。
5.3、IntentFlag 的常用值
IntentFlag 的種類很多,我們這裡就只挑選幾個平時常用的來講解一下。
5.3.1、FLAG_ACTIVITY_NEW_TASK
系統會尋找或建立一個新的 Task 來放置目標 Activity,尋找時依據目標 Activity 的 taskAffinity 屬性進行匹配,如果找到一個 Task 的 taskAffinity 與之相同,就將目標壓入此 Task 中,如果查詢無果,則建立一個新的 Task,並將該 Task 的 taskAffinity 值設定為目標 Activity 的 taskAffinity,將目標 Activity 放置於此 Task 中 。
5.3.1.1、程式碼演示
設定 IntentFlag 的方法:
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
第
一
種
情
況
\color{red}{第一種情況}
第一種情況:以 FLAG_ACTIVITY_NEW_TASK 方式啟動 SecondActivity,但是 SecondActivity 不新增 taskAffinity 屬性,我們來看下效果:
可以看到,我們雖然以 FLAG_ACTIVITY_NEW_TASK 啟動,但是兩個 Activity 所在的 Task 還是同一個,這是為什麼呢?那是因為如果一個 Activity 沒有顯示的指明該 Activity 的 taskAffinity 屬性,那麼它的這個屬性就等於 Application 所指明的 taskAffinity,如果 Application 也沒有指明,那麼該 taskAffinity 的值就等於包名。 也就是說此時 SecondActivity 和 MainActivity 兩個 taskAffinity 的值都是包名,所以 SecondActivity 肯定會被放入 MainActivity 所在的棧中了。
第 二 種 情 況 \color{red}{第二種情況} 第二種情況:以 FLAG_ACTIVITY_NEW_TASK 方式啟動 SecondActivity,並且 SecondActivity 設定 taskAffinity 屬性:
<activity android:name=".SecondActivity"
android:taskAffinity="flag.newIntent.test"/>
我們來看下效果:
可以看到這時候 SecondActivity 和 MainActivity 已經不在同一個棧裡面了。
5.3.2、FLAG_ACTIVITY_SINGLE_TOP
同四種啟動模式中的 singleTop,這裡就不演示了。
5.3.3、FLAG_ACTIVITY_CLEAR_TOP
同四種啟動模式中的 singleTask,這裡也不演示。
5.3.4、FLAG_ACTIVITY_REORDER_TO_FRONT
這個啟動模式的意思是如果棧中已經存在 Activity 例項,會將它拿到棧頂,不會啟動新 Activity,也不會刪除它之上的 Activity 例項。
5.3.4.1、程式碼演示
我們先來看下效果:
我們在 MainActivity 裡面啟動 SecondActivity,然後在 SecondActivity 裡面啟動 ThirdActivity,然後再在 ThirdActivity 裡面通過 FLAG_ACTIVITY_REORDER_TO_FRONT 的方式啟動 SecondActivity,這個時候因為棧中已經有 SecondActivity 例項了,所以會把該例項拿到棧頂,並且不會銷燬 SecondActivity 之上的所有例項,所以此時棧自底向上的 Activity 例項順序是 MainActivity --> ThirdActivity --> SecondActivity。
六、小結
這篇文章主要講了 Activity 的五種啟動方法,包括三種顯示啟動和兩種隱式啟動,又講了單和多 Activity 的生命週期,以及在 AndroidManifest 中通過 lunchMode 設定 Activity 的啟動模式和通過Intent.setFlag() 方法設定 Activity 的啟動模式。
下一篇文章我們將會講解在 Activity 中利用 Intent 傳參、利用Bundle傳遞資料、複雜資料的傳遞以及啟動系統 Activity的方法。
相關文章
- Android 四大元件之 ActivityAndroid元件
- Android四大元件之ActivityAndroid元件
- Android 四大元件之 " Activity "Android元件
- Android四大元件之Activity篇Android元件
- 【Android】安卓四大元件之Activity(二)Android安卓元件
- Android面試常客--四大元件之ActivityAndroid面試元件
- 四大元件之Activity元件
- Android四大元件——Activity——Activity的生命週期Android元件
- Android四大元件之Activity----重新認識Android(4)Android元件
- 四大元件之Activity_Fragment元件Fragment
- 第六章:四大元件之Activity元件
- Android之四大元件Android元件
- Android必知必會的四大元件 -- Activity篇Android元件
- 重溫Android四大元件—Activity的生命週期Android元件
- 四大元件之 Activity_任務和返回棧元件
- Android 四大元件之 ServiceAndroid元件
- Android 四大元件之" Service "Android元件
- 詳解Android中的四大元件之一:Activity詳解Android元件
- Android 四大元件之 BroadcastReceiverAndroid元件AST
- Android四大元件之Service篇Android元件
- Android四大元件之BroadcastReceiverAndroid元件AST
- Android 四大元件之“ BroadcastReceiver ”Android元件AST
- Android 元件系列-----Activity初步Android元件
- Android 四大元件之 ContentProviderAndroid元件IDE
- Android四大元件之BroadcastReceiver篇Android元件AST
- Android四大元件之Service,以及IntentServiceAndroid元件Intent
- Android四大元件之ContentProviderAndroid元件IDE
- Android 四大元件之" ContentProvider "Android元件IDE
- Android之ActivityAndroid
- Android深入四大元件(六)Android8.0 根Activity啟動過程(前篇)Android元件
- Android深入四大元件(七)Android8.0 根Activity啟動過程(後篇)Android元件
- Android四大元件之ContentProvider篇Android元件IDE
- Android四大元件之——BroadcastReceiver介紹Android元件AST
- Android學習之四大元件(二)——serviceAndroid元件
- 完全理解android Activity啟動模式LauchMode (深入Activity與任務棧)Android模式
- 重溫Android四大元件(二)—Activity的啟動模式與標誌位Android元件模式
- Android學習之四大元件(四)——BroadcastReceiverAndroid元件AST
- Android Activity的四大啟動模式詳解Android模式