Android 四大組件之Activity

前言

Hi,大家好,又見面啦,上一期我們講了如何安裝AS,是不是已經有小夥伴迫不及待的創建了自己的項目並開始嘗試了呢?那麼這一期我們主要爲大家介紹Activity。作爲Android的四大組件之一,Activity佔據着非常重要的作用。本文將圍繞Android的生命週期、啓動模式、基本配置等方面進行介紹。

簡介

應用程序的每一個界面都是一個Activity,所以也有人稱其爲視圖界面。從字面的意思去理解,Activity具有活動的意思,我們在應用中進行的操作都是集中在Activity上面完成,例如撥號、拍照、發送email、看地圖。每一個activity被給設置到一個窗口,在上面可以繪製交互界面。 一個應用程序通常由多個activities組成,他們通常是鬆耦合關係,通常一個應用程序包含有一個主Activity,即點擊桌面圖標的時候首先進入的Activity。

Android創建與啓動

以一個簡單的Activity的創建與使用示說明:

創建

img

在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 的生命週期如下圖:

img

(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 的啓動模式。

在探究什麼是啓動模式之前要弄請幾個問題:

  1. 啓動模式原理(什麼是任務棧)?
  2. 爲什麼會需要啓動模式?
  3. 四種任務棧的特點?
  4. 使用方式
  5. 應用場景
什麼是任務棧

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 個數。下面是方法和其對應運行時對應結果。

img

這樣造成數據沉餘,重複數據太多,最終可能還會導致內存溢出(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只有一個實例,並且只能單獨的存在一個任務棧中。

使用方式

啓動模式一般分爲兩種:

  1. 在 AndroidManifes.xml 中 ,找到聲明 Activity 的位置,在 Actvity XML 屬性 android:launchMode="standard",其他模式(singleTop,singleTask,singleInstance) 聲明。
  2. 在代碼中跳轉 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
常見使用場景

這裏是一些在開發中常見的業務場景頁面使用的頁面啓動模式:

img

結語

作爲Android的四大組件之一,並且也是項目開發過程中最常用到的,小夥伴們要深刻理解,並把它靈活的運用到項目中,當然這些也是面試中會問到的最基礎問題。

PS:如果還有未看懂的小夥伴,歡迎加入我們的QQ技術交流羣:892271582,裏面有各種大神回答小夥伴們遇到的問題哦~

img

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章