天天看點

Android Activity詳解

1.什麼是Activity

Activity是Android提供的四大元件之一,是進行Android開發必不可少的元件.Activity是一個界面的載體,它提供螢幕進行互動.可以把它與html頁面進行類比,html頁面由各種各樣的标簽組成,而Activity則可以由各種控件組成.每個Activity都會獲得一個用于繪制其使用者界面的視窗,視窗可以充滿哦螢幕也可以小于螢幕并浮動在其他視窗之上。

一個應用通常是由多個彼此松散聯系的Activity組成,一般會指定應用中的某個Activity為主活動,也就是說首次啟動應用時給使用者呈現的Activity。将Activity設為主活動的方法,如下面代碼所示需要在AndroidManifest檔案中添加以下内容

<application>
     ....
    <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     </activity>
     ....
</application>   
           

當然Activity之間可以進行互相跳轉,以便執行不同的操作。每當新Activity啟動時,舊的Activity便會停止,但是系統會在堆棧也就是傳回棧中保留該Activity。當新Activity啟動時,系統也會将其推送到傳回棧上,并取得使用者的操作焦點。當使用者完成目前Activity并按傳回按鈕時,系統就會從堆棧将其彈出銷毀,然後回複前一Activity.

當一個Activity因某個新Activity啟動而停止時,系統會通過該Activity的生命周期回調方法通知其這一狀态的變化。Activity因狀态變化每個變化可能有若幹種,每一種回調都會提供執行與該狀态相應的特定操作的機會

2.建立Activity

要建立Activity,必須建立Activity的子類。在子類中實作Activity在生命周期的各種狀态之間轉變時(例如建立 Activity、停止 Activity、恢複 Activity 或銷毀 Activity 時)系統調用的回調方法。Android Studio中建立項目預設建立的代碼為

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
           

onCreate()方法:必須實作的方法,系統在建立Activity時調用此方法。您應該在實作内初始化Activity的必要元件,必須在此方法調用setContentView(),用來定義Activity使用者界面布局(XML檔案)

3.在清單檔案中聲明Activity

每次建立的Activity都需要在AndroidManifest檔案中添加如下内容,并将元素添加為元素的子項

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >
           

4.啟動Activity

作為主活動,在應用開啟的時候就會系統建立,而使用者不僅僅隻需要主活動界面,使用者需要界面的跳轉,而界面的跳轉也是其他活動界面(Activity)啟動。

4.1 Activity啟動方式

在Activity啟動中涉及到Intent這個API,在Android中提供了Intent機制來協助應用間的互動與通訊,Intent負責對應用中一次操作的動作、動作涉及資料、附加資料進行描述,Android則根據此Intent的描述,負責找到對應的元件,将 Intent傳遞給調用的元件,并完成元件的調用。

Intent不僅可用于應用程式之間,也可用于應用程式内部的Activity/Service之間的互動。是以,可以将Intent了解為不同元件之間通信的“媒介”,專門提供元件互相調用的相關資訊

Intent有七大屬性:

  1. component(元件):目的元件
  2. action(動作):用來表現意圖的行動
  3. category(類别):用來表現動作的類别
  4. data(資料):表示與動作要操縱的資料
  5. type(資料類型):對于data範例的描寫
  6. extras(擴充資訊):擴充資訊
  7. Flags(标志位):期望這個意圖的運作模式

顯示啟動

這應該用的是最多的一個啟動方式了,先在AndroidManifest.xml裡配置activity,然後進行如下操作:

Intent intent = new Intent(MainActivity.this,CloneActivity.class); 
startActivity(intent);
           

隐式啟動

它與顯示啟動最大差別就是不需要在Intent的執行個體化中傳參, 但是需要在AndroidManifest.xml給該activity配置intentfilter屬性,啟動代碼如下

<intent-filter>
    <action android:name="com.mangoer.activityreview"></action>
    <category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
           
Intent intent = new Intent();
intent.setAction("com.mangoer.activityreview");
startActivity(intent);
           

隐式啟動的過濾過程如圖

Android Activity詳解

一般顯示啟動用于同一APP内,隐式啟動用于啟動APP外部活動,如果有多個元件被比對成功,就會以對話框清單的方式讓使用者進行選擇。每個Intent中隻能指定一個action,但卻能指定多個category;類别越多,動作越具體,意圖越明确

在Intent添加類别可以添加多個類别,那就要求被比對的元件必須同時滿足這多個類别,才 能比對成功。操作Activity的時候,如果沒有類别,須加上預設類别

比如打開百度:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data=Uri.parse("http://www.baidu.com");
intent.setData(data);
startActivity(intent);
           

有時候我們跳轉到别的activity後,希望能夠攜帶一些資料傳回到原activity,那就需要用到startActivityForResult

4.2 Activity啟動模式

啟動模式允許你去定義如何将一個activity的執行個體和目前任務棧進行關聯,有兩種方式來定義啟動模式

  1. 使用manifest檔案:在manifest檔案中聲明一個activity的時候指定launchMode屬性
  2. 使用Intent flag參數:當使用Intent啟動activity的時候,可以在Intent中加入flag來指定新啟動的activity如何與目前任務進行關聯

如果一個被啟動的activity在manifest裡定義了啟動模式,然後在使用Intent啟動的時候也設定了flag定義啟動模式,那麼Intent中的定義模式将會覆寫manifest中的定義

在manifest定義啟動模式

通過設定launchMode屬性來定義,有四種可選參數:

  • standard: 這也是預設啟動模式,即标準模式;如果在該檔案中聲明activity的時候不指定這個參數值,這個activity就模式使用這種模式;它的意思是每啟動一個activity都會重新建立一個該activity的執行個體加入到目前任務中,會走完整的生命周期函數,就算任務中已經存在了這個activity的執行個體還是會建立。這樣就會出現上面說的一個activity在傳回棧中存在多個執行個體,這其實是非常消耗資源的。
  • singleTop: 即棧頂複用模式,這個中文翻譯很有意思,給出了兩個很重要的點,棧頂和複用;也就是說如果要啟動的activity在傳回棧内已經存在了一個執行個體并且還處于棧頂的位置,那麼就不會在重新建立一個執行個體了,而是複用這個activity;複用展現在哪呢,就是調用這個activity的onNewIntent方法,而不會走onCreate-onStart-onResume這個建立邏輯了;如果這個activity不在棧頂,那麼還是會重新建立的。這種模式一般運用場景是一個Activity被頻繁推到棧頂的情況,比如IM聊天,有很多消息過來了,不可能每點選一個消息就去建立一個Activity;新聞推送,也不可能每次點選推送消息,就去建立一個Activity
  • singleTask: 即棧内複用模式,也是一種單例模式;當啟動的activity如果在棧内有執行個體,不管在不在棧頂都會複用這個執行個體,将其置于棧頂,調用這個activity的onNewIntent方法,并且将其上面的所有activity進行出棧處理,全部銷毀。

    這裡有個注意點:android系統會檢測要啟動的activity的affinity和目前任務的affinity是否相同,如果相同就會把這個activity放入到目前任務中,不同的話就會建立一個新的任務。而同一個程式中所有的activity的affinity預設都是相同的,不同的程式是不同的,這樣啟動别的應用的這種模式的activity會建立一個新的任務,啟動自己應用的activity不會建立新的任務。這種模式運用場景比較少,一般用在比較特殊的頁面,比如使用者被簽退了,需要重新跳轉到登陸頁面,這時候需要将之前的頁面全部銷毀,因為跟session相關的資料需要重新初始化

  • singleInstance: 即單例模式,即這個activity自己獨享一個任務,所在的傳回棧裡面隻有這個activity。

    比如給activity2設定singleInstance模式,從activity1跳轉到activity2,activity2跳轉到activity3,這時候按傳回鍵會傳回到activity1.因為Activity2獨自占用一個任務棧,而activity1和activity2共用一個任務棧

    再舉一個例子,Android系統内置的浏覽器程式聲明自己浏覽網頁的Activity始終應該在一個獨立的任務當中打開,也就是通過在元素中設定"singleInstance"啟動模式來實作的。這意味着,當你的程式準備去打開Android内置浏覽器的時候,新打開的Activity并不會放入到你目前的任務中,而是會啟動一個新的任務。而如果浏覽器程式在背景已經存在一個任務了,則會把這個任務切換到前台,不會再重新建立。

使用Intent Flags 定義啟動模式

使用方法就是在使用startActivity的時候建構Intent,對Intent加入一個flag來改變Activity與任務的關聯模式

  • FLAG_ACTIVITY_NEW_TASK: 當Intent對象包含這個标記時,系統會尋找或建立一個新的task來放置目标Activity,尋找時依據目标Activity的taskAffinity屬性進行比對,如果找到一個task的taskAffinity與之相同,就将目标Activity壓入此task中,如果查找無果,則建立一個新的task,并将該task的taskAffinity設定為目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一個應用中Activity的taskAffinity都使用預設值或都設定相同值時,應用内的Activity之間的跳轉使用這個标記是沒有意義的,因為目前應用task就是目标Activity最好的宿主
  • FLAG_ACTIVITY_SINGLE_TOP: 設定了這個flag,如果要啟動的Activity在目前任務中已經存在了,并且還處于棧頂的位置,那麼就不會再次建立這個Activity的執行個體,而是直接調用它的onNewIntent()方法;否則會再建立這個activity;這種flag和在launchMode中指定"singleTop"模式所實作的效果是一樣的。
  • FLAG_ACTIVITY_CLEAR_TOP: 設定了這個flag,如果要啟動的Activity在目前任務的棧頂,就會銷毀這個執行個體并重新建立這個activity;如果不在棧頂,還是銷毀已存在的執行個體并清空這個執行個體上面的所有activity,最後重新建立這個activity。

    如果将Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP兩個結合用,如果要啟動的Activity已經存在任務棧而且不在棧頂,那麼會清空這個activity以上的所有activity,并回調這個activity的onNewIntent,不會重新建立這個activity;如果處于棧頂,就直接回調onNewIntent

taskAffinity參數

affinity可以用于指定一個Activity更加願意依附于哪一個任務,在預設情況下,同一個應用程式中的所有Activity都具有相同的affinity,是以,這些Activity都更加傾向于運作在相同的任務當中。當然了,你也可以去改變每個Activity的affinity值,通過元素的taskAffinity屬性就可以實作了。

taskAffinity屬性接收一個字元串參數,你可以指定成任意的值(經我測試字元串中至少要包含一個),但必須不能和應用程式的包名相同,因為系統會使用包名來作為預設的affinity值。

通常可以與allowTaskReparenting屬性配合使用,設定為true時,Activity就擁有了一個轉移所在任務的能力。具體點來說,就是一個Activity現在是處于某個任務當中的,但是它與另外一個任務具有相同的affinity值,那麼當另外這個任務切換到前台的時候,該Activity就可以轉移到現在的這個任務當中。

5. 結束Activity

通過調用Activity的**finish()方法來結束Activity還可以通過調用finishActivity()**結束之前啟動的活動

關于finishActivity()的了解:

你通過 MainActivity 來啟動 ActivityA (使用 startActivityForResult 方法),那麼你在 MainActivity 這個類中需要重寫 onActivityResult() 這個方法,

然後,你可以在 onActivityResult() 中通過 finishActivity() 方法去結束掉 ActivityA

6. 管理Activity生命周期

周期即活動從開始到結束所經曆的各種狀态。生命周期即活動從開始到結束所經曆的各個狀态。從一個狀态到另一個狀态的轉變,從無到有再到無,這樣一個過程中所經曆的狀态就叫做生命周期。

Activity本質上有四種狀态:

  1. 運作(Active/Running): Activity處于活動狀态,此時Activity處于棧頂,是可見狀态,可以與使用者進行互動
  2. 暫停(Paused): 當Activity失去焦點時,或被一個新的非全面屏的Activity,或被一個透明的Activity放置在棧頂時,Activity就轉化為Paused狀态。此刻并不會被銷毀,隻是失去了與使用者互動的能力,其所有的狀态資訊及其成員變量都還在,隻有在系統記憶體緊張的情況下,才有可能被系統回收掉
  3. 停止(Stopped): 當Activity被系統完全覆寫時,被覆寫的Activity就會進入Stopped狀态,此時已不在可見,但是資源還是沒有被收回
  4. 系統回收(Killed): 當Activity被系統回收掉,Activity就處于Killed狀态,它所儲存的資訊和成員變量都不在了。

如果一個活動在處于停止或者暫停的狀态下,系統記憶體缺乏時會将其結束(finish)或者殺死(kill)。這種非正常情況下,系統在殺死或者結束之前會調用**onSaveInstance()方法來儲存資訊,同時,當Activity被移動到前台時,重新啟動該Activity并調用onRestoreInstance()**方法加載保留的資訊,以保持原有的狀态。

Android Activity詳解
Android Activity詳解
  1. Activity 的整個生命周期發生在 onCreate() 調用與 onDestroy() 調用之間。

    您的 Activity 應在 onCreate()中執行“全局”狀态設定(例如定義布局),并釋放 onDestroy()中的所有其餘資源。例如,如果您的 Activity 有一個在背景運作的線程,用于從網絡上下載下傳資料,它可能會在onCreate() 中建立該線程,然後在onDestroy() 中停止該線程。

  2. Activity 的可見生命周期發生在 onStart() 調用與 onStop() 調用之間。

    在這段時間,使用者可以在螢幕上看到 Activity 并與其互動。例如,當一個新 Activity 啟動,并且此 Activity 不再可見時,系統會調用onStop()。您可以在調用這兩個方法之間保留向使用者顯示 Activity 所需的資源。例如,您可以在onStart() 中注冊一個 BroadcastReceiver 以監控影響 UI的變化,并在使用者無法再看到您顯示的内容時在 onStop()中将其取消注冊。在 Activity 的整個生命周期,當 Activity 在對使用者可見和隐藏兩種狀态中交替變化時,系統可能會多次調用 onStart() 和 onStop()。

  3. Activity 的前台生命周期發生在 onResume() 調用與 onPause() 調用之間。

    在這段時間,Activity 位于螢幕上的所有其他 Activity 之前,并具有使用者輸入焦點。Activity 可頻繁轉入和轉出前台 — 例如,當裝置轉入休眠狀态或出現對話框時,系統會調用 onPause()。由于此狀态可能經常發生轉變,是以這兩個方法中應采用适度輕量級的代碼,以避免因轉變速度慢而讓使用者等待。

小結:

當Activity啟動時,依次會調用onCreate(),onStart(),onResume(),而當Activity退居背景時(不可見,點選Home或者被新的Activity完全覆寫),onPause()和onStop()會依次被調用。當Activity重新回到前台(從桌面回到原Activity或者被覆寫後又回到原Activity)時,onRestart(),onStart(),onResume()會依次被調用。當Activity退出銷毀時(點選back鍵),**onPause(),onStop(),onDestroy()**會依次被調用,到此Activity的整個生命周期方法回調完成。

Android Activity詳解
Android Activity詳解

參考:

  1. activity的四種狀态說明
  2. Activity開發–掌握Activity隐式顯示啟動方法 scheme跳轉協定 生命周期及啟動模式配置
  3. Android Activity詳解

繼續閱讀