Android之Activity全面解析

NO IMAGE

前言

基於最近要準備去面試,特意系統的複習了下Android基礎,看到Activity這塊時,發現很多都忘了,而且之前也沒有系統的學習和寫筆記記錄,所以,特此寫下這篇關於Activity的一些理解,旨在幫助大家更好的理解Activity.

Activity是什麼?

Activity是一個Android應用程序組件(也稱為Android四大組件之一),它提供了一個屏幕,用戶可以通過該屏幕進行交互以執行某些操作,例如撥打電話,拍照,發送電子郵件或查看地圖。每個活動都有一個窗口,用於繪製其用戶界面。窗口通常填滿屏幕,但可能比屏幕小,並漂浮在其他窗口的頂部.

Android應用程序通常由多個彼此鬆散綁定的Activity組成。通常,應用程序中的一個Activity被指定為“主要”Activity,該Activity在首次啟動應用程序時呈現給用戶。然後,每個Activity可以啟動另一個Activity以執行不同的操作。每次新Activity開始時,前一個Activity都會停止,但系統會將Activity保留在後臺堆棧中(“後堆棧”)。當一個新的Activity開始時,它會被推到後面的堆棧上,並引起用戶的注意。後棧遵循基本的“ 後進先出”堆棧機制,因此,當用戶完成當前活動並按下”後退按鈕”時,它從堆棧彈出(並銷燬),之前的活動恢復。(後臺堆棧將在後面為大家詳細介紹。)

如何創建Activity

要創建Activity,您必須創建Activity(或其現有子類)的子類。在子類中,您需要實現當Activity在其生命週期的各個狀態之間轉換時系統調用的回調方法,例如在創建,停止,恢復或銷燬活動時。兩個最重要的回調方法是:

public class ExampleActivity extends AppCompatActivity {

 @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
//您必須實現此方法。系統在創建Activity時調用此方法。在您的實施中,您應該初始化Activity的基本組成部分。最重要的是,您必須在此處調用以定義Activity用戶界面的佈局。
        setContentView();
    }


//系統將此方法稱為用戶離開您的Activity的第一個指示(儘管並不總是意味著Activity正在被銷燬)。這通常是您應該提交應該在當前用戶會話之外保留的任何更改的地方(因為用戶可能不會回來)。

@Override
    protected void onPause() {
        super.onPause();
        //在此處應該提交應該在當前用戶會話之外保留的任何更改的地方
    }

}

在訪問Activity時,必須在manifest中聲明此Activity,

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

你也可以指定Activity的<intent-filter>過濾器,如下:

<activity android:name = “. ExampleActivity ” android:icon = “@ drawable / app_icon” >
 <intent-filter> <action android:name = “android.intent.action.MAIN” /> 
<category android:name = “ android.intent.category.LAUNCHER“ />
 </ intent-filter>
 </ activity>  

如何啟動Activity

您可以通過調用啟動另一個Activity,通過startActivity()方法,並將Intent傳遞給您要啟動的Activity。intent指定要啟動的確切Activity或描述您要執行的操作類型(系統為您選擇適當的活動,甚至可以來自不同的應用程序)。Intent(意圖)還可以攜帶少量數據以供啟動的活動使用。

  • 啟動指定自建的Activity
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

此種啟動又叫做顯示Intent .

  • 啟動其他類型的Activity
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

此種啟動又叫做隱式Intent .

有時候,我們可能需要從上一個Activity接收返回數據結果,這時,我們就需要另外一種啟動方式了.

在這種情況下,通過調用startActivityForResult()(而不是startActivity())來啟動Activity。然後,要從後續Activity接收結果,就需要實現onActivityResult()回調方法。完成後續Activity後,它會在您的onActivityResult() 方法中返回結果。

private void pickContact() {
    // Create an intent to "pick" a contact, as defined by the content provider URI
    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult(intent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
        // Perform a query to the contact's content provider for the contact's name
        Cursor cursor = getContentResolver().query(data.getData(),
        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
        if (cursor.moveToFirst()) { // True if the cursor is not empty
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
            String name = cursor.getString(columnIndex);
            // Do something with the selected contact's name...
        }
    }
}

關閉Activity

您可以通過調用其finish()方法來關閉活動。您還可以關閉之前通過調用啟動的單獨活動finishActivity()。

接下來便是整個Activity最核心的地方了,只要搞清楚一下內容,Activity也就理解的差不多了

Activity生命週期詳解

Activity之所以能夠成為Android四大組件之一,原因便是其具有非常靈活的生命週期回調方法,通過實現回調方法來管理Activity的生命週期對於開發強大而靈活的應用程序至關重要。Activity的生命週期直接受其與其他Activity,其任務和後臺堆棧的關聯的影響。

  • Activity基本上存在於三種狀態:
  1. 恢復 onResume()
    Activity位於屏幕的前景並具有用戶焦點。

2.已暫停 onPause()
另一項Activity是在前臺並具有焦點,但這一項仍然可見。也就是說,另一個Activity在這個Activity的頂部可見,該Activity部分透明或不覆蓋整個屏幕。暫停的Activity完全處於活動狀態(Activity 對象保留在內存中,它保留所有狀態和成員信息,並保持附加到窗口管理器),但可以在極低內存情況下被系統殺死。

3.停止 onStop()
該Activity完全被另一個Activity遮擋(活動現在位於“背景”中)。停止的Activity也仍然存在(Activity 對象保留在內存中,它維護所有狀態和成員信息,但不 附加到窗口管理器)。但是,它不再對用戶可見,並且當其他地方需要內存時,它可能被系統殺死。
如果Activity暫停或停止,系統可以通過要求它完成(調用其finish()方法)或簡單地終止其進程來從內存中刪除它。當活動再次打開時(在完成或殺死之後),必須全部創建它。

Activity完整生命週期回調方法

public class ExampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The activity is being created.
    }
    @Override
    protected void onStart() {
        super.onStart();
        // The activity is about to become visible.
    }
    @Override
    protected void onResume() {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
    @Override
    protected void onPause() {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void onStop() {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
}

注意:在執行任何工作之前,以上這些生命週期方法的實現必須始終調用超類實現,如上面的示例所示。

  1. Activity中存在的三個循環生命週期
  • Activity的整個生命週期
    Activity的整個生命週期發生在呼叫onCreate()和呼叫之間onDestroy()。您的Activity的整個生命週期應該執行“全局”狀態的設置(例如定義佈局)onCreate(),並釋放所有剩餘資源onDestroy()。

  • Activity的可見生命週期
    Activity的可見生命週期發生在呼叫onStart()和呼叫之間onStop()。在此期間,用戶可以在屏幕上看到Activity並與之交互。例如,onStop()在新Activity開始時調用,並且此Activity不再可見。在這兩種方法之間,您可以維護向用戶顯示Activity所需的資源。例如,你可以註冊一個 BroadcastReceiver在onStart()監視會影響您的用戶界面的變化,並在註銷它onStop()時,用戶將不再能夠看到你所顯示的內容。該系統可能會調用onStart()和onStop()活動的整個生命週期內多次為可見和隱藏用戶之間的活動交替。

  • Activity的前景生命週期
    Activity的前景生命週期發生在調用onResume()和調用之間onPause()。在此期間,Activity位於屏幕上的所有其他活動之前,並且具有用戶輸入焦點。Activity可以頻繁地進出前臺 – 例如,onPause()當設備進入睡眠狀態或出現對話框時調用。因為這種狀態可以經常轉換,所以這兩種方法中的代碼應該相當輕量級,以避免使用戶等待的緩慢轉換。

2.Activity生命週期循環圖

Android之Activity全面解析

圖中說明了這些循環以及活動在狀態之間可能採用的路徑。矩形表示當活動在狀態之間轉換時可以實現的回調方法。

3.Activity生命週期的回調方法摘要

MethodDescriptionKillable after?Next
onCreate()在第一次創建活動時調用。這是您應該進行所有常規靜態設置的地方 – 創建視圖,將數據綁定到列表等等。如果捕獲了該狀態,則此方法將傳遞包含活動先前狀態的Bundle對象NoonStart()
onRestart()在Activity停止後,再次啟動之前調用。NoonStart()
onStart()在活動變得對用戶可見之前調用。NoonResume()或onStop()
onResume()在活動開始與用戶交互之前調用。此時,活動位於活動堆棧的頂部,用戶輸入轉到活動堆棧。NoonPause()
onPause()當系統即將開始恢復另一個活動時調用。此方法通常用於將未保存的更改提交到持久數據,停止動畫以及可能消耗CPU的其他事物,等等。它應該做很快的事情,因為下一個Activity在返回之前不會恢復。YesonResume()或onStop()
onStop()當活動不再對用戶可見時調用。這可能是因為它正在被銷燬,或者是因為另一個活動(現有的或新的活動)已經恢復並且正在覆蓋它。YesonRestart()或onDestroy()
onDestroy()在活動被銷燬之前調用。這是活動將收到的最後一個電話。可以調用它,因為活動正在完成(有人調用finish()它),或者因為系統暫時銷燬此活動實例以節省空間。您可以使用該isFinishing()方法區分這兩種情況。Yesnothing

其中Killable after?表示系統是否可以在方法返回後隨時終止託管Activity的進程,而不執行Activity代碼的下一個回調方法.

因為onPause()是三個允許Killable after方法中第一個執行的,一旦活動被創建,onPause()是在回調過程中能夠保證執行的最後一個方法,如果系統必須在緊急情況下恢復記憶,是會調用onPause()方法的,但是onStop()和onDestroy()可能不被調用。因此,您應該使用onPause()將關鍵的持久性數據(例如用戶編輯)寫入存儲。而不是onStop()或onDestroy().

所以在此處特別聲明,要保存用戶輸入數據,需要在onPause()中執行,而不是在onStop()和onDestroy()中.

生命週期回調的順序是明確定義的,特別是當兩個Activity在同一個進程中而其中一個正在啟動另一個時。以下是ActivityA啟動ActivityB時發生的操作順序:

1.ActivityA的onPause()方法執行。
2.ActivityB的onCreate(),onStart()和onResume() 方法執行順序。(ActivityB現在具有用戶關注點。)
3.然後,如果ActivityA在屏幕上不再可見,則onStop()執行其方法。

這種可預測的生命週期回調序列允許您管理從一個Activity到另一個Activity的信息轉換。例如,如果您必須在第一個Activity停止時寫入數據庫以便以下Activity可以讀取它,那麼您應該在onPause()期間而不是在onStop()期間寫入數據庫。

3.保存Activity活動狀態
當Activity暫停或停止,該Activity的活動狀態會被保持,因為Activity對象在暫停或停止時仍保留在內存中 – 有關其成員和當前狀態的所有信息仍然存在。因此,Activity會默認保留用戶在活動中所做的任何更改,以便當活動返回到前臺時(當它“恢復”時),那些更改仍然存在。

但是,當系統銷燬Activity以恢復內存時,Activity對象被破壞,因此係統不能完好無損地恢復它的活動狀態。在這種情況下,您可以通過實施額外的回調方法來確保保留有關活動狀態的重要信息,該方法允許您保存有關活動狀態的信息:

onSaveInstanceState()  //用來保存用戶狀態信息

onSaveInstanceState() 在Activity受破壞之前,系統會自動調用。系統會傳遞一個Bundle對象,您可以使用諸如putString()和putInt()之類的方法將關於Activity的狀態信息保存為名稱 - 值的鍵值對.

然後,如果系統終止您的應用程序進程,系統將重新創建活動並將其Bundle傳遞給Activity的onCreate()和onRestoreInstanceState()。使用這些方法之一,您可以從中提取已保存的狀態Bundle並恢復活動狀態。如果沒有要恢復的狀態信息,則Bundle傳遞給您的是null(這是第一次創建活動時的情況)。

如下圖所示:

Android之Activity全面解析

活動返回到用戶焦點且狀態完好無損的兩種方式:活動被銷燬,然後重新創建,活動必須恢復先前保存的狀態,或者活動停止,然後恢復,活動狀態仍然存在完整。

注意:onSaveInstanceState()在您的活動被銷燬之前不能保證會被調用,因為在某些情況下不需要保存狀態(例如當用戶使用“ 返回”按鈕離開您的活動時,因為用戶是明確的關閉活動)。如果系統調用onSaveInstanceState(),則會在onPause()和onStop()之前執行.

再者就是,即使不執行任何操作並且未實現onSaveInstanceState(),只要Activity沒有被銷燬,Activity也會默認實現onSaveInstanceState()來恢復某些活動狀態.例如EditText輸入的文字,但前提是控件需要有android:id,否則不會默認保存狀態.

  1. onSaveInstanceState()常用場景

某些設備配置可能會在運行時更改(例如屏幕方向,鍵盤可用性和語言)。發生此類更改時,Android會重新創建正在運行的活動(系統調用onDestroy(),然後立即調用onCreate()).處理此類重新啟動的最佳方法是使用onSaveInstanceState()和onRestoreInstanceState()(或onCreate())來保存和恢復Activity活動狀態.

Activity進出後臺任務和後臺堆棧詳解

每個應用程序通常包含多個Activitys,每個Activity都應圍繞用戶可以執行的特定操作進行設計,並可以啟動其他Activity,甚至可以啟動設備上其他應用程序中存在的Activity.

Android設備主屏幕是大多數任務的起始位置。當用戶觸摸應用程序啟動器中的圖標(或主屏幕上的快捷方式)時,該應用程序的任務將到達前臺。如果應用程序不存在任務(最近未使用該應用程序),則會創建一個新任務,該應用程序的“主”Activity將作為堆棧中的根Activity打開。

1.後臺堆棧
後臺堆棧指的是Activitys在後臺任務中的排列規則,按”後進先出”排列.

例如當前Activity啟動另一個Activity時,新Activity將被推到堆棧頂部並獲得焦點。之前的Activity仍在堆棧中,但已停止。當活動停止時,系統將保留其用戶界面的當前狀態。當用戶按下“ 返回” 按鈕時,當前Activity將從堆棧頂部彈出(活動被銷燬),之前的Activity將恢復(其UI的先前狀態將恢復)。堆棧中的活動永遠不會重新排列,只能在當前Activity啟動時從堆棧推送和彈出到堆棧中,並在用戶使用Back按鈕退出時彈出.因此,後臺堆棧作為“後進先出”對象結構操作。

如下圖所示:

Android之Activity全面解析

圖中表示任務中的每個新Activity如何將項添加到後臺堆棧。當用戶按下“ 返回”按鈕時,將破壞當前Activity並恢復先前的Activity。

如果用戶繼續按Back,則彈出堆棧中的每個Activity以顯示前一個Activity,直到用戶返回主屏幕(或任務開始時運行的任何活動)。從堆棧中刪除所有活動後,該任務不再存在。

2.後臺任務
任務是一個內聚單元,當用戶開始新任務或通過主頁按鈕進入主屏幕時,可以移動到“後臺背景” 。在後臺,任務中的所有Activitys都會停止,但任務的後臺堆棧保持不變 – 任務在發生另一項任務時完全失去焦點.

如下圖所示:

Android之Activity全面解析

兩個任務:任務B在前臺接收用戶交互,而任務A在後臺,等待恢復,這就是Android上的多任務處理的一個示例。

注意:可以在後臺同時保存多個任務。但是,如果用戶同時運行許多後臺任務,系統可能會開始銷燬後臺活動以恢復內存,從而導致活動狀態丟失。

由於後臺堆棧中的活動永遠不會重新排列,如果您的應用程序允許用戶從多個Activitys啟動特定Activity,則會創建該Acticity的新實例並將其推送到堆棧(而不是引入任何先前的活動實例)到頂部。因此,應用程序中的一個Acticity可能會被多次實例化(甚至來自不同的任務).

如下圖所示:

Android之Activity全面解析

如果不希望多次實例化Acticity,則可以修改此行為。通常來說關於這部分內容是不太需要我們去更改的,所以這裡我就不介紹了,有興趣的同學可以自行翻閱[官方文檔].

3.定義Activity啟動模式

啟動模式允許您定義Activity的新實例與當前任務的關聯方式。您可以通過兩種方式定義不同的啟動模式:

  • 使用 manifest file(manifest 清單文件)

在清單文件中聲明Activity時,可以使用 元素的launchMode屬性指定Activity在啟動時應如何與任務關聯。

launchMode 屬性分配四有種不同的啟動模式 :

modesdescription
“standard” (默認模式)默認。系統在啟動它的任務中創建Activity的新實例,並將意圖路由到該實例。Activity可以多次實例化,每個實例可以屬於不同的任務,一個任務可以有多個實例。
“singleTop”如果Activity的實例已存在於當前任務的頂部,則系統通過調用其onNewIntent()方法將意圖路由到該實例,而不是創建Activity的新實例。Activity可以多次實例化,每個實例可以屬於不同的任務,一個任務可以有多個實例(但只有當後端堆棧頂部的Activity不是Activity的現有實例時)。
“singleTask”系統創建新任務並在新任務的根目錄下實例化Activity。但是,如果Activity的實例已存在於單獨的任務中,則系統會通過調用其onNewIntent()方法將意圖路由到現有實例,而不是創建新實例。一次只能存在一個Activity實例。
“singleInstance”相同”singleTask”,區別在於:系統不啟動任何其他Activity納入控制實例的任務。Activity始終是其任務的唯一成員; 任何由此開始的Activity都在一個單獨的任務中打開。

無論Activity是在新任務中啟動還是在與啟動它的Activity相同的任務中啟動,“ 返回”按鈕始終會將用戶帶到上一個Activity。但是,如果啟動指定singleTask啟動模式的活動,則如果後臺任務中存在該Activity的實例,則將整個任務帶到前臺。此時,後端堆棧現在包括堆棧頂部提出的任務中的所有Activitys。

如下圖所示:

Android之Activity全面解析

  • 使用 Intent flags(意圖傳遞)

當您調用時startActivity(),您可以在其中包含一個標誌Intent,聲明新Activity應如何(或是否)與當前任務相關聯。

Intent flagsdescription
FLAG_ACTIVITY_NEW_TASK與上述”singleTask” 效果相同
FLAG_ACTIVITY_SINGLE_TOP與上述”singleTop”效果相同
FLAG_ACTIVITY_CLEAR_TOP如果正在啟動的Activity已在當前任務中運行,則不會啟動該Activity的新實例,而是銷燬其上的所有其他Activitys,並將此意圖傳遞給Activity的恢復實例

注意:如果指定Activity的啟動模式是 “standard”,它也將從堆棧中刪除,並在其位置啟動新實例以處理傳入的意圖。這是因為在啟動模式下,總是為新意圖創建一個新實例”standard”。

4.清理後堆棧

如果用戶長時間離開任務,系統將清除除根Activity之外的所有Activitys的任務。當用戶再次返回任務時,僅還原根Activity。系統以這種方式運行,因為在很長一段時間之後,用戶可能已經放棄了之前正在做的事情並返回任務以開始新的事情。

可以使用一些Activity屬性來修改此行為:

attributedescription
alwaysRetainTaskState如果任務的根Activity將此屬性設置為”true”,則不會發生剛才描述的默認行為。即使經過很長一段時間,任務仍會保留堆棧中的所有Activity
clearTaskOnLaunch與”alwaysRetainTaskState”正好相反,即使在離開任務片刻之後,用戶也始終以初始狀態返回任務
finishOnTaskLaunch此屬性類似clearTaskOnLaunch,但它在單個活動上運行,而不是在整個任務上運行。它還可以導致任何活動消失,包括根活動。當它設置為時”true”,活動仍然是當前會話的任務的一部分。如果用戶離開然後返回任務,它將不再存在

深呼一口氣,不知不覺寫了這麼多,關於Activity的基本解析到這裡就告一段落了,寫完這些我對Activity又有了更深刻的理解和認識了,本文不止對Activity表面解析,更是深入到了一些底層驅動,希望看完這些能對你有所幫助.

歡迎關注作者darryrzhong,更多幹貨等你來拿喲.

請賞個小紅心!因為你的鼓勵是我寫作的最大動力!

更多精彩文章請關注

相關文章

1024程序員節最新福利之2018最全大數據資料集合

1024程序員節最新福利之2018最全Android資料集合

1024程序員節最新福利之2018最全java資料集合

1024程序員節最新福利之2018最全H5前端資料集