Android四大元件之Activity

koro發表於2020-09-21

Activity 生命週期

onCreate():表示Activity正在被建立,常用來初始化工作,比如呼叫setContentView載入介面佈局資源,初始化Activity所需資料等

onRestart():表示Activity正在重新啟動,一般情況下,當前Acitivty從不可見重新變為可見時,OnRestart就會被呼叫

onStart():表示Activity正在被啟動,此時Activity可見但不在前臺,還處於後臺,無法與使用者互動

onResume():表示Activity獲得焦點,此時Activity可見且在前臺並開始活動,這是與onStart的區別所在

onPause():表示Activity正在停止,此時可做一些儲存資料、停止動畫等工作,但是不能太耗時,因為這會影響到新Activity的顯示,onPause必須先執行完,新Activity的onResume才會執行

onStop():表示Activity即將停止,可以做一些稍微重量級的回收工作,比如登出廣播接收器、關閉網路連線等,同樣不能太耗時

onDestroy():表示Activity即將被銷燬,這是Activity生命週期中的最後一個回撥,常做回收工作、資源釋放

在這裡插入圖片描述

建議成對記錄: onCreate- onDestroy(建立-銷燬)丨 onStart-onStop(啟動-停止)丨 onResume-onPush(可見-隱藏)丨 onRestart(重啟)


啟動 Activity A 跳轉 Activity B 再返回 Activity A 會呼叫哪些方法?如果B是透明主題或者是DialogActivity呢 ?

A 和 B 均為普通Activity時:

啟動 Activity A

A onCreate
A onStart
A onResume

跳轉 Activity B

A onPause
B onCreate 
B onStart
B onResume
A onStop

返回 Activity A

B onPause
A onRestart
A onStart
A onResume
B onStop
B onDestory

當 B 為 DialogActivity 或 透明主題時時:

啟動 Activity A

A onCreate
A onStart
A onResume

跳轉 Activity B

A onPause
B onCreate 
B onStart
B onResume
此時 Activity A 並不會 onStop

返回 Activity A

B onPause
此時 Activity 並不會 onRestart、onStart,因為它就沒被 onStop,生命週期間的方法都是對應的
A onResume
B onStop
B onDestory

Activity onSaveInstanceState() 的作用及呼叫場景

onSaveInstanceState() 可在 Activity 被破壞前儲存現有佈局物件的資訊,如螢幕旋轉。它一般與 onRestoreInstanceState() 一起使用

onSaveInstanceState 內可透過Bundle物件以 key-value 形式儲存當前頁面資料,在 onRestoreInstanceState 內可透過相應 key 取出資料

    private static String USER_INPUT_NAME = "user_input_name";
    private static String USER_INPUT_PASD = "user_input_pasd";
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // 儲存
        outState.putString(USER_INPUT_NAME, "liyongli");
        outState.putString(USER_INPUT_PASD, "01234567");
        super.onSaveInstanceState(outState);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 檢查是否為重新建立被破壞的Activity
        if (savedInstanceState != null) {
            // 輸出儲存值
            Log.e("==" , savedInstanceState.getString(USER_INPUT_NAME));
            Log.e("==" , savedInstanceState.getString(USER_INPUT_PASD));
        }else{
            Log.e("==" , "正常建立");
        }
    }

Activity 的四種啟動模式及應用場景

Standare:預設啟動模式,每次都會在虛擬棧頂建立一個例項

SingleTop:檢查該 Activity 的例項是否位於棧頂,位於棧頂時複用,非棧頂時建立新例項。應用場景:列表的詳情頁、狀態列訊息通知頁

SingleTask:該 Activity 在整個應用中只存在一個例項,啟動此 Activity 時會檢查虛擬棧中是否存在它的例項,如果存在直接複用,並把當前Activity之上所有例項全部出棧。應用場景:APP Tab 頁

SingleInstance:具備 singleTask 模式的所有特性。該模式的 Activity 會啟動一個新的任務棧來管理 Activity 例項,並且該例項在整個系統中只有一個。無論從那個任務棧中啟動該 Activity,都會是該 Activity 所在的任務棧轉移到前臺,從而使Activity顯示。主要作用是為了在不同程式裡共享一個 Activity 例項。應用場景:系統撥打電話頁、系統通訊錄、地圖或導航類APP


Activity Intent Flags 動態設定與靜態設定

動態設定 Flags:程式碼中透過 Intent 的 addFlags 方法指定, Intent.addFlags(Intent.Flag_Activity_***);

Intent intent = new Intent(Context, ****.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

靜態設定 Flags:Manifest.xml 檔案中配置 android:launchMode="***"

<activity
	android:name="***"  
	···
	···
	android:launchMode="singleInstance">
</activity>

Activity Flags

Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT, // 本flag一般不由應用程式碼設定,singleTask模式時系統會給你設定。
 Intent.FLAG_ACTIVITY_CLEAR_TASK,  // 本flag能造成在新活動啟動前,與新活動關聯的任務被清空。也就是說,新活動成為新任務的根,舊的活動都被結束了。本flag只能與FLAG_ACTIVITY_NEW_TASK聯合使用
 Intent.FLAG_ACTIVITY_CLEAR_TOP, // 1. 新活動已在當前任務中時,在新活動上面的活動會被關閉,新活動不會重新啟動,只會接收new intent。 2. 新活動已在任務最上面時:如果啟動模式是"multiple" (預設的),並且沒新增FLAG_ACTIVITY_SINGLE_TOP,那麼活動會被銷燬重新建立;如果啟動模式是其他的,或者新增了FLAG_ACTIVITY_SINGLE_TOP,那麼只會呼叫活動的onNewIntent()。 3. 跟FLAG_ACTIVITY_NEW_TASK聯合使用效果很好:如果用於啟動一個任務中的根活動,會把該任務移到前面並清空至root狀態。這特別有用,比如用於從notification manager中啟動活動。
 Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, // 已廢棄。API 21後用FLAG_ACTIVITY_NEW_DOCUMENT。
 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, // 新活動不會儲存在最近啟動的活動列表中。
 Intent.FLAG_ACTIVITY_FORWARD_RESULT, // 1. (當前活動由源活動啟動)本intent從當前活動啟動新活動時,源活動的接收目標會從當前活動轉移為新活動。新活動呼叫setResult的資料會傳送給源活動。
 Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY, // 本flag一般不由應用程式碼設定,活動從歷史棧中啟動(長按home鍵)時系統會給你設定。
 Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT, // 本flag只在分屏多視窗模式下使用。新活動會顯示在舊活動旁邊。本flag只能跟FLAG_ACTIVITY_NEW_TASK聯合使用。並且如果你想建立一個已存在活動的新例項,那麼要設定FLAG_ACTIVITY_MULTIPLE_TASK。
 Intent.FLAG_ACTIVITY_MULTIPLE_TASK, //  1. 用於建立一個新任務,並啟動一個活動放進去;總是跟FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用;單獨用FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK時,會在已存在的任務中尋找匹配的Intent,找不到才會建立一個新任務;使用了本flag不會尋找匹配的Intent,無條件建立一個新任務。2. **用了FLAG_ACTIVITY_NEW_TASK就不要用本flag,除非你啟動的是應用的launcher。** 跟FLAG_ACTIVITY_NEW_TASK聯合使用能防止把已存在的任務移到前面,會為新活動建立一個新任務,無論已存在的任務中有沒有新活動。3. 因為預設安卓系統中沒有提供視覺化的任務管理,所以你不應該使用本flag,除非給使用者提供可以回到其他任務的方法。4. 單獨用本flag而不用FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK是無效的。
 Intent.FLAG_ACTIVITY_NEW_DOCUMENT, //1. 本flag會給啟動的活動開一個新的任務記錄。使用了本flag或documentLaunchMode屬性時,相同活動的多例項會在最近任務列表中產生不同的記錄。 2. 使用本flag比使用documentLaunchMode屬性更好,因為documentLaunchMode屬性會跟活動繫結,而flag只在需要時新增。 3. 注意本flag的預設詞義,活動銷燬後最近任務列表中的入口不會移除。這跟使用FLAG_ACTIVITY_NEW_TASK不一樣,後者活動銷燬後入口會馬上移除。你可以用FLAG_ACTIVITY_RETAIN_IN_RECENTS改變這個行為。 4. 本flag可以跟FLAG_ACTIVITY_MULTIPLE_TASK聯合使用。單獨使用時跟manifest活動中定義documentLaunchMode="intoExisting"效果相同,聯合使用時跟manifest活動中定義documentLaunchMode="always"效果相同。
 Intent.FLAG_ACTIVITY_NEW_TASK, //  1. 新活動會成為歷史棧中的新任務(一組活動)的開始。 2. 通常用於具有"launcher"行為的活動:讓使用者完成一系列事情,完全獨立於之前的活動。 3. 如果新活動已存在於一個為它執行的任務中,那麼不會啟動,只會把該任務移到螢幕最前。 4. 如果新活動要返回result給啟動自己的活動,就不能用這個flag。
 Intent.FLAG_ACTIVITY_NO_ANIMATION, //  1. 本flag會阻止系統展示活動的當前狀態到另一個狀態之間的轉移動畫。這並不意味著永遠沒有動畫 -- 如果另一項活動的改變在當前展示的活動啟動前發生並且沒有使用本flag,那麼動畫還會展示。當你要進行一系列活動操作,但是使用者看到的動畫不應該由第一項改變來驅動,而是由下一項。
 
 Intent.FLAG_ACTIVITY_NO_HISTORY, //  1. 新活動不會保留在歷史棧中,一旦使用者切換到其他頁面,新活動會馬上銷燬。 2. 舊活動的onActivityResult()方法永遠不會被觸發。
 Intent.FLAG_ACTIVITY_NO_USER_ACTION, // 1. 本flag會阻止當前最前面活動的onUserLeaveHint回撥,在它被新啟動的活動造成paused狀態時。 2. 通常,一個活動在受到使用者操作而從前面移走的時候會呼叫上面的回撥。該回撥標誌著活動生命週期中的一個點,在該點活動會隱藏它想要顯示的”直到使用者看到“的東西,比如閃爍的LED燈。 3. 如果一個活動曾經由非使用者驅動的事件比如來電或鬧鐘啟動,應該在startActivity中新增本flag,以保證暫停時活動知道使用者並沒有看到通知。
 Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP, //  1. 本intent從當前活動啟動新活動時,當前活動不會被視為頂端活動,不管是決定傳intent給頂端還是啟動新活動。新活動被當做頂端活動使用,假設當前活動立即銷燬了。
 Intent.FLAG_ACTIVITY_REORDER_TO_FRONT, //  1. 如果新活動已在任務中,用本flag啟動會將它移到任務的歷史棧的前面。 2. 如果用了FLAG_ACTIVITY_CLEAR_TOP,本flag就無效。
 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, // 新活動在新任務中啟動或者被放到一個已存在任務的頂端時,會被當做任務的前門來啟動。這會導致任何相關性的活動在適當狀態下需要擁有這個任務(無論移動活動到它裡面或者是移走),或者在需要時簡單地重置任務到初始狀態。
 Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS, //  1. 預設情況下由FLAG_ACTIVITY_NEW_DOCUMENT建立的新紀錄,使用者關閉時(按返回鍵或其他方式結束)它在最近任務中的入口會被移除。如果你想保留入口,就用本flag。 2. 接收的活動可以用autoRemoveFromRecents屬性或者呼叫Activity.finishAndRemoveTask()來覆蓋本請求。
 Intent.FLAG_ACTIVITY_SINGLE_TOP, //  1. 新活動已存在歷史棧的頂端時就不會重新啟動。
 Intent.FLAG_ACTIVITY_TASK_ON_HOME, // 本flag會造成新的啟動任務放在當前主頁活動任務(如果有的話)的頂端。也就是說,在任務中按返回鍵總是會回到主頁,即使上一個使用者看到的活動不是主頁。本flag只能與FLAG_ACTIVITY_NEW_TASK聯合使用。123456789101112131415161718192021222324252627282930313233343536373839

Activity 與 Window、View 的關係

Activity 構造時會初始化一個 Window,它的具體實現是 PhoneWindow,每個Activity 對應一個 PhoneWindow

PhoneWindow 內包含 ViewRoot ,它既可以是一個 ViewGroup,也可以是單一View,表示根檢視,Activity 透過 setContentView() 將 View 設定在 PhoneWindow 之上

ViewRoot 可以透過 addView()、removeView()、updateViewLayout() 實現新增或管理 View

所以 Window / PhoneWindow 是中間人,是橋樑,可以使Activity 和 View 功能解耦,各司其職

當產生觸控、點選事件時,WindowManagerService 會首先接收事件,並回撥相應 Activity 提供的 onClickListener、onKeyDown 此類的回撥函式處理


Activity 橫豎屏切換時的生命週期變化

onPuase
onStop
onDestory
onCreate
onStart
onResume123456

其實是相當於回收後重建,若需保留一些資料,可透過 onSaveInstanceState()onSaveInstanceState()


啟動其他應用的 Activity

在 Activity、Service 和 BroadcastReceiver 均可以啟動其它應用的 Activity,

  • 設定Intent的className:
        Intent intent = new Intent(Intent.ACTION_VIEW);
        // 設定包名
        String packageName = "com.example.mylife.anotherapp";
        // 設定類名
        String className = "com.example.mylife.anotherapp.MainActivity";
        intent.setClassName(packageName, className);
        // 或者設定 setComponent
        //intent.setComponent(new ComponentName("com.example.mylife.anotherapp","com.example.mylife.anotherapp.MainActivity"));
        // 新增附帶引數
        Bundle bundle = new Bundle();
        bundle.putString("id", "this message is from project B ");
        intent.putExtras(bundle);
        intent.putExtra("token", android.os.Process.myPid());
        startActivityForResult(intent, 1);1234567891011121314
  • 隱式Intent的action方式:
    先在 Activity A 中清單檔案中設定 intent-filter ; action
        <activity android:name=".B">
            <intent-filter>
                <action android:name="android.intent.action.B"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>123456

在 Activity B (或 Service B)中 Intent action

Intent intent=new Intent("android.intent.action.B");
startActivity(intent);12


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69984284/viewspace-2722753/,如需轉載,請註明出處,否則將追究法律責任。

相關文章