前言 Hi,大家好,又見面啦,上一期我們講瞭如何安裝AS,是不是已經有小伙伴迫不及待的創建了自己的項目並開始嘗試了呢?那麼這一期我們主要為大家介紹Activity。作為Android的四大組件之一,Activity占據著非常重要的作用。本文將圍繞Android的生命周期、啟動模式、基本配置等方面進行 ...
Hi,大家好,又見面啦,上一期我們講瞭如何安裝AS,是不是已經有小伙伴迫不及待的創建了自己的項目並開始嘗試了呢?那麼這一期我們主要為大家介紹Activity。作為Android的四大組件之一,Activity占據著非常重要的作用。本文將圍繞Android的生命周期、啟動模式、基本配置等方面進行介紹。
簡介
應用程式的每一個界面都是一個Activity,所以也有人稱其為視圖界面。從字面的意思去理解,Activity具有活動的意思,我們在應用中進行的操作都是集中在Activity上面完成,例如撥號、拍照、發送email、看地圖。每一個activity被給設置到一個視窗,在上面可以繪製交互界面。 一個應用程式通常由多個activities組成,他們通常是松耦合關係,通常一個應用程式包含有一個主Activity,即點擊桌面圖標的時候首先進入的Activity。
Android創建與啟動
以一個簡單的Activity的創建與使用示說明:
創建
在Androd Studio 新建項目完成後,會自動創建一個 Java 文件,這個文件就是 Activity,因為它繼承系統 framework 層提供的 Activity,這裡 AppCompatActivity 是 Activity 的子類,我們的 MainActivity 間接繼承 Activity。
並且你會看到 MainActivity 強制重寫了 onCreate 方法,在 onCreate 中,通過 setContentView 為 Activity 設置我們自定義的頁面佈局文件。
註冊Activity
在 manifest 中註冊Activity
<activity android:name=".MainActivity" android:configChanges="orientation|screenSize" android:label="@string/app_name" android:launchMode="standard"> <intent-filter> <action android:name="myactoin2" /> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
Activity 必須在 AndroidManifest.xml 註冊,如果沒有註冊這 Activity 就不能正常運行,其實在正常情況下在使用Android 中的四大組件(Activity,Service,BrocastReceiver,ContentProvider)時都需要再 AndroidManifest.xml 中註冊。在上面的 xml 註冊信息中,其中 <inten-filter>中指定
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
表明這個Activity是主Activity,在Android系統點擊應用圖標首先進入主Activity。
啟動
Activity是通過Intent用來在應用程式的Activity間啟動、停止和傳輸。
啟動Activity的三種方法:
1、顯示啟動
在這裡註冊了第二個Activity ---- SecondActivity ,並且牢記前面的註冊操作,我們把 SecondActivity 註冊到 Manifest 文件中。現在就可以在 MainActivity 中啟動 SecondActivity。
Intent intent = new Intent(this, SecondActivity.class); //通過上下文Context和SecondActivity.java類的Class對象,創建 Intent 對象 startActivity(intent);//調用系統Framework 層提供的方法,啟動 SecondActivity。
2、隱式啟動
若 SecondActivity 在AndroidManifest.xml文件中配置 intent-filter 的 action 和 category、data,如下:
<intent-filter> <action android:name="myaction2"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="mycategory" /> </intent-filter>
那麼可以通過如下方式啟動 SecondActivity :
Intent intent = new Intent("myaction2"); startActivity(intent);
3、預設啟動
通過桌面圖標點擊應用圖標進入程式的第一個Activity,因其啟動方式有別上述兩個方式,將其劃分為第三類的啟動方式。 若Activity在AndroidManifest.xml文件的intent-filter的action和category,如下:
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
那麼,點擊桌面的應用圖標即可啟動Activity。
註:如果在N個Activity中都配置上述的action和category,那麼桌面會有N個應用的圖標,點擊不同的圖標會進入對應的Activity。
Activity的生命周期
Activity 的生命周期如下圖:
(1) onCreate
表示Activity正在被創建,這是第一個執行的方法,在Activity的生命周期中只執行一次。在這個方法中做一些初始化工作,比如調用setContentView去載入界面佈局,初始化Activity所需要的數據等。後續調用onStart()。
(2) onRestart
表示Activity正在重新啟動,一般情況下,當前的Activity從不可見的狀態變為可見狀態時,onRestart就會被調用。這種情形一般是用戶操作出現所致,比如用戶按Home鍵回到桌面或者用戶打開了一個新的Activity,這時候Activity就會暫停,接著用戶又回到該Activity。後續調用onStart()。
(3) onStart
表示Activity正在被啟動,即將開始。這個時候Activity是可見的,但是還沒有出現在前臺,不能和用戶進行交互。這個時候可以理解為Activity已經顯示出來,但是我們還看不到。後續的方法是onResume()。
(4) onResume
表示Activity可見,並且已經出現在前臺並開始活動,能和用戶正常進行交互。需要註意的是onStart和onResume的區別,二者都是Activity可見,但是onStart時Activity還在後臺,而onResume時Activity到了前臺了,這時候可以開啟動畫或者獲取獨占性設備的操作如打開相機、獲取麥克風等。
(5) onPause
表示Activity由前臺轉到後臺,正常情況下,緊接著onStop就會被調用。這時仍然可見。如果這時候快速地回到當前Activity,那麼onResume會被調用,這類情況屬於極端情況,用戶操作很難重現這一場景。此時可以做一些存儲數據,停止動畫等操作,但是註意不能太耗時,如果太耗時會影響到新的Activity的顯示。onPause是先執行完,新的Activity的onCreate才會執行。onResume和onPause相對應。
(6) onStop
表示Activity即將停止,當前的Activity對用戶不在可見。可稍微做些重量級的回收操作。後續的操作可能是onRestart或者onDestroy或者一直保持這個狀態。
(7) onDestory
表示Activity正在被銷毀,是生命周期的最後一個回調,也是只調用一次。發生的條件是Activity本身已經執行完畢,或者系統資源不足需要回收資源將Activity銷毀。
我們考慮如下幾類情況: 1、當一個Toast彈出的時候,會發生回調麽? No 2、當一個AlertDialog彈出的時候,會發生回調麽? No, 如果AlertDialog獲取焦點,Activity會觸發onWindowFocusChanged回調 3、當一個PopWindow彈出的時候,會發生回調麽? No, 如果PopWindow獲取焦點,如mPopupWindow.setFocusable(true),Activity會觸發onWindowFocusChanged回調。 4.橫豎屏切換時,會造成Activity被銷毀然後重新創建。若在Activity配置android:configChanges="orientation",橫豎屏切換時,只觸發onConfigurationChanged( )回調,Activity不會被重新創建。
啟動模式
Activity 有四種啟動模式,不同的模式,對應這 Activity 對象的創建於復用策略,可以在 Manifest 和 代碼中指定 Activity 的啟動模式。
在探究什麼是啟動模式之前要弄請幾個問題:
-
啟動模式原理(什麼是任務棧)?
-
為什麼會需要啟動模式?
-
四種任務棧的特點?
-
使用方式
-
應用場景
什麼是任務棧
Android 任務棧又稱為 Task,它是一個棧類型的數據結構:先進先出。它用於存儲我們的 Activity 組件。
每次打開一個新的 Activity 或 退出一個 Activity 都會在任務棧的結構中添加或減少一個 Activity,一個任務棧包含了一個 Activity 集合。Android 系統可以通過 Task 有序的管理每個 Activity ,並決定那個 Activity 與用戶進行交互:只用在棧頂的 Activity 才可以跟用戶進行交互。
在應用程式退出時,必須把所有任務棧中的 Activity 清除棧時,任務棧才會被銷毀。當然任務棧可以移動到後臺,並且保存每個 Activity 的狀態。可以有序的給用戶列出Activity的任務,同時也不會丟失 Activity 的信息。
應用程式中可能不止一個任務棧,某系情況情況下,單獨的一個 Activity 可以獨享一個任務棧,也會存在一個任務棧的 Activity 可以來自不同的 App,同一個 App 中的 Activity 可能在不同的任務棧當中。
為什麼會需要啟動模式
在應用程式開發過程中,一般都需要在多個 Activity 組件之間跳轉,也可能需要在本應用中打開其他應用的可復用的 Activity。在開發過程中需要跳轉到原來已經開啟的 Activity 實例,此時我們希望這個 Activity 可以被重用而不是再重新創建一個新的 Activity 實例,但根據 Android 系統的預設行為,每次都會為我們創建一個新的 Activity 實例對象並添加到任務棧中,而且 Activity 的數據和信息狀態都將會被保留 。
我們可以在 MainActivity 中添加一個按鈕,點擊按鈕跳轉到 SecondActivity,然後在 SecondActivity 中添加兩個按鈕,點擊一個按鈕跳轉到 MainActvity,在另一個按鈕的點擊事件中添加如下代碼:
//獲取ActivityMananger ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); //獲取任務棧 可能是多個 List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(5); //獲取當前的任務棧 ActivityManager.RunningTaskInfo runningTaskInfo = runningTasks.get(0); //獲取當前任務棧中 Activity 個數,即當前沒有換存活的 Activity 實例個數。 int numRunning = runningTaskInfo.numRunning; //Log 列印信息 Log.e("SecondActivity", "numRunning" + numRunning);
上面代碼不用深究,主要目的是想說明系統預設情況下,當前任務棧中存活的 Activity 實例個數。當我們在 MainActvity 中點擊按鈕跳轉到 SecondActivity ,當跳轉到 SecondActivity 在點擊第一個按鈕跳轉到 MainActivity ,不斷重覆這個操作。最後當跳轉的 SecondActivity 點擊第一個按鈕獲取當前任務棧中的 Activity 個數。下麵是方法和其對應運行時對應結果。
這樣造成數據沉餘,重覆數據太多,最終可能還會導致記憶體溢出(OOM)。為解決這些問題,Android 系統提供了一套 Activity的啟動模式來修改預設的 Activity 啟動模式。
四種任務棧的特點
-
Standard 模式(一般模式)
系統預設模式,每次啟動一個Activity都會重新創建一個新的實例,而不管Activity是否已經創建了一個實例。
-
SingTop (棧頂復用模式)
棧頂復用模式,系統啟動時,系統會啟動當前棧頂Activity是不是要啟動的Activity,如果是則不需要創建新的Activity而直接引用這個Activity,如果不是那麼創建新的Activity。系統會回調Activity的onNewIntent()的方法。
-
SingTask(棧內復用模式)
棧內復用模式,如果棧內已經存在了一個Activity的實例,那麼Activity不會被重新創建,同時這個Activity的onNewIntent()方法會被回調,並將該Activity實例置於棧頂,原先處於該實例頂部的Activity實例會被出棧銷毀。如果是其他程式啟動Activity,那麼它會重新創建一個任務棧。
-
SingleInstance(單一實例模式)
單實例模式,是singleTask的加強版,具有singleTask所有特點,並且此種模式下Activity只有一個實例,並且只能單獨的存在一個任務棧中。
使用方式
啟動模式一般分為兩種:
-
在 AndroidManifes.xml 中 ,找到聲明 Activity 的位置,在 Actvity XML 屬性 android:launchMode="standard",其他模式(singleTop,singleTask,singleInstance) 聲明。
-
在代碼中跳轉 Activity 時,利用 Intent 指定 Flag 標誌位來使用啟動模式。示例代碼如下:
Intent intent = new Intent(this, SecondActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//Flag startActivity(intent);
setFlags方法說明
//使用一個新的Task來啟動Activity,但每個Activity都將在一個新的Task中。 Intent.FLAG_ACTIVITY_NEW_TASK //使用singleTop模式來啟動一個Activity。 Intent.FLAG_ACTIVITY_SINGLE_TOP //使用singleTask模式來啟動一個Activity。 Intent.FLAG_ACTIVITY_CLEAR_TOP //使用singleTask模式來啟動一個Activity,使用這種方式啟動Activity,當Activity啟動其他Activity的時候,該Activity會被銷毀,不入棧。 Intent.FLAG_ACTIVITY_NO_HISTORY //方式無法指定 SingleInstance 模式,SingleInstances 只能在 AndroidManifest.xml 中聲明。 Intent.setFlags
常見使用場景
這裡是一些在開發中常見的業務場景頁面使用的頁面啟動模式:
結語
PS:如果還有未看懂的小伙伴,歡迎關註我們WXGZH:下碼看花,裡面有各種大神回答小伙伴們遇到的問題哦~