Activity知識總結

在Android開發中承擔的主要角色

1、App的入口

你要想用一個app肯定要打開這個app才能使用,主Activity是用戶點擊這個app之后第一個啟動的Activity,這個Activity啟動后才能與用戶有其他更多的交互,就像是Java程序的入口函數main一樣,main函數的執行才能使整個應用跑起來,所以Activity是app的入口。所有的程序都有入口,找到入口才能慢慢的解析整個程序的運行過程。

2、顯示和控制用戶的邏輯界面

所有寫給用戶使用的程序必然會設計一個好的交互界面,用戶在這個界面進行功能選擇和使用,在Android系統中,承擔起與用戶交互的界面是由View來呈現的,但是View的顯示是靠Activity來控制。

所以Activity總是承擔著顯示用戶界面和控制用戶操作邏輯的角色。

生命周期

程序都是有生命周期的,目前程序在什么生命周期就做該生命周期內的事,別做超越生命周期范圍內的事,就像是人生一樣,是什么階段就做什么階段該做的事,不多做,也別少做。Android系統已經給Activity的生命周期定義很多回調函數,你需要做的就是熟悉這些回調函數,知道在執行這個回調函數的時候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.
    }
}

下圖是Google官方的Activity生命周期圖,已經非常詳盡的說明個Activity生命周期之間的跳轉和哪種情況下Activity會被kill掉。


image

創建生命周期

  • onCreate:設置Activity要呈現的View,創建Activity需要的資源。
  • onDestory:釋放onCreat中創建的資源。

可見生命周期

  • onStart :Activity 開始變得可見。
  • onStop : Activity 開始變得不可見。onPause中不能進行耗時操作,會影響到新Activity的顯示。因為onPause必須執行完,新的Activity的onResume才會執行。
  • onRestart :如果一個Activity在onStop狀態,開始變得可見的時候調用。

可交互生命周期

  • onResume: Activity可以獲取焦點并與用戶交互。
  • onPause : Activity丟失焦點,不再與用戶交互。

以下是摘自<Google官方文檔>:

image

名為“是否能事后終止?”的列表示系統是否能在不執行另一行 Activity 代碼的情況下,在方法返回后隨時終止承載 Activity 的進程。 有三個方法帶有“是”標記:(onPause()、onStop() 和 onDestroy())。由于 onPause() 是這三個方法中的第一個,因此 Activity 創建后,onPause() 必定成為最后調用的方法,然后才能終止進程 — 如果系統在緊急情況下必須恢復內存,則可能不會調用 onStop() 和 onDestroy()。因此,您應該使用 onPause() 向存儲設備寫入至關重要的持久性數據(例如用戶編輯)。不過,您應該對 onPause() 調用期間必須保留的信息有所選擇,因為該方法中的任何阻止過程都會妨礙向下一個 Activity 的轉變并拖慢用戶體驗。

在是否能在事后終止?列中標記為“否”的方法可從系統調用它們的一刻起防止承載 Activity 的進程被終止。 因此,在從 onPause() 返回的時間到 onResume() 被調用的時間,系統可以終止 Activity。在 onPause() 被再次調用并返回前,將無法再次終止 Activity。

注:無法保證系統會在銷毀您的 Activity 前調用 onSaveInstanceState(),因為存在不需要保存狀態的情況(例如用戶使用“返回”按鈕離開您的 Activity 時,因為用戶的行為是在顯式關閉 Activity)。 如果系統調用 onSaveInstanceState(),它會在調用 onStop() 之前,并且可能會在調用 onPause() 之前進行調用。

注:由于無法保證系統會調用 onSaveInstanceState(),因此您只應利用它來記錄 Activity 的瞬態(UI 的狀態)— 切勿使用它來存儲持久性數據,而應使用 onPause() 在用戶離開 Activity 后存儲持久性數據(例如應保存到數據庫的數據)。

您只需旋轉設備,讓屏幕方向發生變化,就能有效地測試您的應用的狀態恢復能力。 當屏幕方向變化時,系統會銷毀并重建 Activity,以便應用可供新屏幕配置使用的備用資源。 單憑這一理由,您的 Activity 在重建時能否完全恢復其狀態就顯得非常重要,因為用戶在使用應用時經常需要旋轉屏幕。

啟動模式

任務棧:任務是指在執行特定作業時與用戶交互的一系列 Activity。 這些 Activity 按照各自的打開順序排列在堆棧(即返回棧)中。設備主屏幕是大多數任務的起點。

standard 標準模式

每次都會創建新的Activity;

singleTop 棧頂復用

當創建的Activity是棧頂時,它的啟動類型是singleTop的那么不會新建Activity,而是調用onNewIntent方法,如果不是棧頂則會新建。

singleTask 棧內復用

該模式是一種單例模式,即一個棧內只有一個該Activity實例。該模式,可以通過在AndroidManifest文件的Activity中指定該Activity需要加載到那個棧中,即singleTask的Activity可以指定想要加載的目標棧。singleTask和taskAffinity配合使用,指定開啟的Activity加入到哪個棧中。

執行邏輯:

  • 在這種模式下,如果Activity指定的棧不存在,則創建一個棧,并把創建的Activity壓入棧內。
  • 如果Activity指定的棧存在,如果其中沒有該Activity實例,則會創建Activity并壓入棧頂,如果其中有該Activity實例,則把該Activity實例之上的Activity殺死清除出棧,重用并讓該Activity實例處在棧頂,然后調用onNewIntent()方法。

應用場景:

大多數App的主頁。對于大部分應用,當我們在主界面點擊回退按鈕的時候都是退出應用,那么當我們第一次進入主界面之后,主界面位于棧底,以后不管我們打開了多少個Activity,只要我們再次回到主界面,都應該使用將主界面Activity上所有的Activity移除的方式來讓主界面Activity處于棧頂,而不是往棧頂新加一個主界面Activity的實例,通過這種方式能夠保證退出應用時所有的Activity都能報銷毀。在跨應用Intent傳遞時,如果系統中不存在singleTask Activity的實例,那么將創建一個新的Task,然后創建SingleTask Activity的實例,將其放入新的Task中。

singleInstance 單例模式

作為棧內復用模式(singleTask)的加強版,打開該Activity時,直接創建一個新的任務棧,并創建該Activity實例放入新棧中。一旦該模式的Activity實例已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的實例。

應用場景:

呼叫來電界面。這種模式的使用情況比較罕見,在Launcher中可能使用。或者你確定你需要使Activity只有一個實例。建議謹慎使用。

開發的場景

1、從A啟動B的流程:

Activity A 和 Activity B

  • 調用A的onPause方法,A失去焦點不可交互;
  • 調用B的onCreate,onStart,onResume,現在B處于前臺可交互;
  • 如果A在屏幕上變得不可見,則調用A的onStop;

2、關于用戶配置信息的保存

要測試應用能否在保持應用狀態完好的情況下自行重啟,您應該在應用中執行各種任務時調用配置變更(例如,更改屏幕方向)。 您的應用應該能夠在不丟失用戶數據或狀態的情況下隨時重啟,以便處理如下事件:配置發生變化,或者用戶收到來電并在應用進程被銷毀很久之后返回到應用。

但是,您可能會遇到這種情況:重啟應用并恢復大量數據不僅成本高昂,而且給用戶留下糟糕的使用體驗。 在這種情況下,您有兩個其他選擇:

在配置變更期間保留對象

允許 Activity 在配置變更時重啟,但是要將有狀態對象傳遞給 Activity 的新實例。利用Fragment實現。當 Android 系統因配置變更而關閉 Activity 時,不會銷毀您已標記為要保留的 Activity 的片段。 您可以將此類片段添加到 Activity 以保留有狀態的對象。

  • 擴展 Fragment 類并聲明對有狀態對象的引用。
  • 在創建片段后調用 setRetainInstance(boolean)。
  • 將片段添加到 Activity。
  • 重啟 Activity 后,使用 FragmentManager 檢索片段。
public class RetainedFragment extends Fragment {

    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}

注意:盡管您可以存儲任何對象,但是切勿傳遞與 Activity 綁定的對象,例如,Drawable、Adapter、View 或其他任何與 Context 關聯的對象。否則,它將泄漏原始 Activity 實例的所有視圖和資源。 (泄漏資源意味著應用將繼續持有這些資源,但是無法對其進行垃圾回收,因此可能會丟失大量內存。)

public class MyActivity extends Activity {

    private RetainedFragment dataFragment;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // find the retained fragment on activity restarts
        FragmentManager fm = getFragmentManager();
        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);

        // create the fragment and data the first time
        if (dataFragment == null) {
            // add the fragment
            dataFragment = new DataFragment();
            fm.beginTransaction().add(dataFragment, “data”).commit();
            // load the data from the web
            dataFragment.setData(loadMyData());
        }

        // the data is available in dataFragment.getData()
        ...
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // store the data in the fragment
        dataFragment.setData(collectMyLoadedData());
    }
}

在此示例中,onCreate() 添加了一個片段或恢復了對它的引用。此外,onCreate() 還將有狀態的對象存儲在片段實例內部。onDestroy() 對所保留的片段實例內的有狀態對象進行更新。

自行處理配置變更

阻止系統在某些配置變更期間重啟 Activity,但要在配置確實發生變化時接收回調,這樣,您就能夠根據需要手動更新 Activity。利用 android:configChanges 和onConfigurationChanged() 實現。

注:自行處理配置變更可能導致備用資源的使用更為困難,因為系統不會為您自動應用這些資源。 只能在您必須避免 Activity 因配置變更而重啟這一萬般無奈的情況下,才考慮采用自行處理配置變更這種方法,而且對于大多數應用并不建議使用此方法。

3、onSaveInstanceState和 onRestoreInstanceState(Bundle)

Activity異常情況下(系統資源緊張,橫豎屏切換)會被調用用來保存和恢復Activity狀態,調用的時序:onSavInstanceState->onStop(If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause()),onStart->onRestoreInstanceState->onResume.

其中onCreate和onRestoreInstanceState方法來恢復Activity的狀態的區別:onRestoreInstanceState回調則表明其中Bundle對象非空,不用加非空判斷。onCreate需要非空判斷。建議使用onRestoreInstanceState。

橫豎屏切換的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()

可以通過在AndroidManifest文件的Activity中指定如下屬性:

android:configChanges = "orientation| screenSize"

來避免橫豎屏切換時,Activity的銷毀和重建,會回調了下面的方法:

    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

4、前后臺棧交互

調用SingleTask模式的后臺任務棧中的Activity,會把整個棧的Actvity壓入當前棧的棧頂。singleTask會具有clearTop特性,會把之上的棧內Activity清除。

前臺棧T1中有Activity A,B,后臺棧T2中有 singleTask標志的Activity C,D,當從B啟動D時會合并這兩個棧成為:A B C D,此時從D開始回退,回退的順序則是D,C,B,A。

當從B啟動C時會合并為A,B,C,D會被清除。

Activity的Flags很多,這里介紹集中常用的,用于設定Activity的啟動模式。可以在啟動Activity時,通過Intent的addFlags()方法設置。

(1)FLAG_ACTIVITY_NEW_TASK
其效果與指定Activity為singleTask模式一致。

(2)FLAG_ACTIVITY_SINGLE_TOP
其效果與指定Activity為singleTop模式一致。

(3)FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位于它上面的Activity都要出棧。如果和singleTask模式一起出現,若被啟動的Activity已經存在棧中,則清除其之上的Activity,并調用該Activity的onNewIntent方法。如果被啟動的Activity采用standard模式,那么該Activity連同之上的所有Activity出棧,然后創建新的Activity實例并壓入棧中。

5、是否所有的數據保存都應該在onPause中執行,并且onPause會一定被執行嗎?

onPause的執行概率會大于onStop,所以在onPause中執行保存最好,但是要快,免得影響程序的執行效率。onPause不是一定會被執行,在關機的時候不會,所以保險起見數據在操作之后最好就保存,而不是非要等到onPause。

參考:
1、Android官網
2、別人的總結

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Activity 一、四種形態 運行狀態: 當 Activity 處于棧的頂層,可見,并可與用戶進行交互 onRe...
    任教主來也閱讀 1,723評論 1 10
  • Activity的生命周期 Activity的創建和銷毀onCreate(): 執行Activity某些基本設置的...
    Showdy閱讀 933評論 0 1
  • 【Android Activity】 什么是 Activity? 四大組件之一,通常一個用戶交互界面對應一個 ac...
    Rtia閱讀 3,847評論 3 18
  • 轉載注明出處:http://www.lxweimin.com/p/c2c2ee4eb48a 1. 簡介 本篇不針對于...
    王三的貓阿德閱讀 2,342評論 2 5
  • 包子的世界 千奇百怪 肉與菜的結合 是不是真的心甘情愿 我倒想知道 當初是誰先出走 舍棄多年的搭檔 去尋找自己的歸屬
    五色浮元子_閱讀 172評論 0 0