關於Activity

前言(Activity)

官方簡介

Activity 是一個應用組件,用戶可與其提供的屏幕進行交互,以執行撥打電話、拍攝照片、發送電子郵件或查看地圖等操做。 每一個 Activity 都會得到一個用於繪製其用戶界面的窗口。窗口一般會充滿屏幕,但也可小於屏幕並浮動在其餘窗口之上。android

一個應用一般由多個彼此鬆散聯繫的 Activity 組成。 通常會指定應用中的某個 Activity 爲「主」Activity,即首次啓動應用時呈現給用戶的那個 Activity。 並且每一個 Activity 都可啓動另外一個 Activity,以便執行不一樣的操做。瀏覽器

如何使用

自定義一個Activity,繼承Activity,在onCreate()生命週期方法中setContentView(layoutId)layoutId是自定義的佈局文件),而後在清單文件中註冊該Activity。安全

重要方法

  • 啓動 Activity 的方法:startActivity(Intent intent)app

  • 結束 Activity 的方法:finish()finishActivity(requestCode)iview

  • 三組生命週期方法ide

    1. 完整生存週期:onCreate() ~ onDestroy()
    2. 可見生存週期:onStart() ~ onStop()
    3. 前臺(可操做)生存週期:onResume() ~ onPause()
  • 數據回收和恢復工具

    • onSaveInstanceState(Bundle outState) 在Activity銷燬前保存重要數據,在onPause方法以後被調用
    • onRestoreInstanceState(Bundle savedInstanceState) 恢復數據,在onResume()方法以前調用
    • onCreate(Bundle savedInstanceState) 這裏也能夠恢復數據

    在這裏插入圖片描述

生命週期方法詳解(官方文檔)

方法 說明 是否能過後終止 後接
onCreate() 首次建立 Activity 時調用。 您應該在此方法中執行全部正常的靜態設置 — 建立視圖、將數據綁定到列表等等。 系統向此方法傳遞一個 Bundle 對象,其中包含 Activity 的上一狀態,不過前提是捕獲了該狀態(請參閱後文的保存 Activity 狀態)。始終後接 onStart()。 onStart()
onRestart() 在 Activity 已中止並即將再次啓動前調用。始終後接 onStart() onStart()
onStart() 在 Activity 即將對用戶可見以前調用。若是 Activity 轉入前臺,則後接 onResume(),若是 Activity 轉入隱藏狀態,則後接 onStop()。 onResume()

onStop()
onResume() 在 Activity 即將開始與用戶進行交互以前調用。 此時,Activity 處於 Activity 堆棧的頂層,並具備用戶輸入焦點。始終後接 onPause()。 onPause()
onPause() 當系統即將開始繼續另外一個 Activity 時調用。 此方法一般用於確認對持久性數據的未保存更改、中止動畫以及其餘可能消耗 CPU 的內容,諸如此類。 它應該很是迅速地執行所需操做,由於它返回後,下一個 Activity 才能繼續執行。若是 Activity 返回前臺,則後接 onResume(),若是 Activity 轉入對用戶不可見狀態,則後接 onStop()。 onResume()

onStop()
onStop() 在 Activity 對用戶再也不可見時調用。若是 Activity 被銷燬,或另外一個 Activity(一個現有 Activity 或新 Activity)繼續執行並將其覆蓋,就可能發生這種狀況。若是 Activity 恢復與用戶的交互,則後接 onRestart(),若是 Activity 被銷燬,則後接 onDestroy()。 onRestart()

onDestroy()
onDestroy() 在 Activity 被銷燬前調用。這是 Activity 將收到的最後調用。 當 Activity 結束(有人對 Activity 調用了 finish()),或系統爲節省空間而暫時銷燬該 Activity 實例時,可能會調用它。 您能夠經過 isFinishing() 方法區分這兩種情形。

特別介紹:onNewIntent(),該方法在要啓動的Activity已經存在,而且不須要從新建立時調用。佈局

啓動方式

顯式啓動:單元測試

//方式1
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);

//方式2
Intent intent = new Intent();
ComponentName componentName = new ComponentName(this,SecondActivity.class);
intent.setComponent(componentName);
startActivity(intent);

//方式3
Intent intent = new Intent();
intent.setClassName("com.hdib","com.hdib.SecondActivity");
startActivity(intent);

// 方式4
startActivityForResult(intent,requestCode);
複製代碼

隱式啓動(詳見 Intent匹配規則):測試

//案例1(發送電子郵件)
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
複製代碼

1、Activity啓動流程

Activity A 啓動 Activity B

Activity A 的 onPause() 方法執行。
Activity B 的 onCreate()、onStart() 和 onResume() 方法依次執行。(Activity B 如今具備用戶焦點。)
而後,若是 Activity A 在屏幕上再也不可見,則其 onStop() 方法執行。

Launcher啓動 MainActivity

  1. Launcher組件向ActivityManagerService發送一個啓動MainActivity的進程間通訊請求。
  2. ActivityManagerService首先將要啓動的MainActivity信息保存起來,而後再向Launcher發送一個進入終止狀態的進程間通訊請求。
  3. Launcher組件進入終止狀態後就會向ActivityManagerService發送一個已經進入終止狀態的進程間通訊請求,以便ActivityManagerService能夠繼續執行MainActivity的啓動。
  4. ActivityManagerService發現用於運行MainActivity的應用程序進程不存在,所以會先啓動一個新的應用程序進程。
  5. 新的應用程序進程啓動後就會向ActivityManagerService發送一個啓動完成的進程間通訊請求,以便ActivityManagerService能夠繼續執行MainActivity的啓動。
  6. ActivityManagerService將第二步保存起來的MainActivity信息發送第四步建立的新的應用程序進程,以便將MainActivity啓動起來。

1、Activity啓動模式

launchMode Description
standard 默認模式,多實例模式。系統老是會啓動一個新的Activity來知足要求——即使已經存在該Activity。
而且它老是歸屬於調用startActivity()將其啓動的那個task。
singleTop 共同點:同上。
不一樣點:當該Activity已經被啓動而且位於目標Task的棧頂時,就經過onNewIntent()方法將Intent傳遞給該Activity,而不是新啓動一個Activity。
singleTask 這樣的Activity在一個Task中只能有一個。
若是該Activity已經啓動,那麼將經過onNewIntent()方法將Intent傳遞給它,並清空棧頂Activity,同時將包含剩餘Activity的整個Task移到前臺。
這種模式容許與其餘Activity在相同的task中,只是要保證該Activity在Task中只有一個就能夠了。
singleInstance 單實例模式,永遠單獨在一個task中。啓動該Activity時,若是Activity實例不存在,必定會從新建立task並將該Activity實例放入其中。

Flag

Flag Description
FLAG_ACTIVITY_NEW_TASK 等同於singleTask模式。如下flag須要與這個flag一塊兒用。
FLAG_ACTIVITY_CLEAR_TASK:清除棧中其餘Activity。
FLAG_ACTIVITY_TASK_ON_HOME:新啓動的Activity放在task棧中Launcher的上面。
FLAG_ACTIVITY_MULTIPLE_TASK:阻止系統恢復一個現有的task,也就是每次都新啓動一個task。
FLAG_ACTIVITY_LAUNCH_ADJACENT:僅用於分屏多窗口模式,新啓動的Activity顯示在啓動它的Activity旁邊,若是須要建立現有Activity的新實例,應同時設置FLAG_ACTIVITY_MULTIPLE_TASK
FLAG_ACTIVITY_BROUGHT_TO_FRONT launchMode中設置singleTask時會自動加上這個標誌。
若是該Activity已經被建立,並且存在於某個task中,此時另一個task啓動該Activity,系統會自動清理該Activity之上的全部Activity
FLAG_ACTIVITY_SINGLE_TOP 等同於singleTop模式。
FLAG_ACTIVITY_CLEAR_TOP 若是要啓動的Activity已經在棧中,那麼須要清除在該Activity之上的全部Activity,並經過onNewIntent()方法將Intent傳遞給該Activity
FLAG_ACTIVITY_PREVIOUS_IS_TOP 相似於FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_NO_HISTORY 該Activity將不會被保存在History Stack中。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 該Activity不會被放在系統最近啓動的Activity列表中。
如進程列表截圖中不會有這個頁面(會獲取上一個頁面的截圖)
按home鍵回到桌面後,在點擊桌面圖標應用從新回到前臺時,也不會顯示這個頁面,而是顯示上一個頁面。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 不管Activity的目標task是新task仍是現有task,都會處於task的上端。
通常要FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET標識配合使用,不過該標識 API 21 之後過期,FLAG_ACTIVITY_NEW_DOCUMENT取代之。
該Activity啓動時,若是目標棧中已經有該Activity,那麼清除其上面的全部Activity。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 系統自動設置,從歷史記錄中啓動
FLAG_ACTIVITY_NO_USER_ACTION 可以使onUserLeaveHint()回調不執行,該方法用於指示用戶將要離開,Activity會退出前臺。
FLAG_ACTIVITY_REORDER_TO_FRONT 若是Activity已經在History stack中,則調整順序使其到棧頂。
FLAG_ACTIVITY_NO_ANIMATION 無動畫啓動Activity
FLAG_ACTIVITY_FORWARD_RESULT 該Flag不能和startActivityForResult()同時使用,表示不接受onActivityResult()回調。
該Flag啓動的Activity若是調用了setResult()方法,那麼回調結果不會傳遞給啓動它的Activity,而是傳遞給前一個Activity。
FLAG_ACTIVITY_MATCH_EXTERNAL Android P Developer Priview中加入
設置後,若是設備上沒有可以處理該intent的app,那麼將會啓動一個instant app來進行處理。
FLAG_ACTIVITY_RETAIN_IN_RECENTS 默認狀況下經過FLAG_ACTIVITY_NEW_DOCUMENT啓動的activity在關閉以後,task中的記錄會相對應的刪除。若是爲了可以從新啓動這個activity你想保留它,就可使用這個flag,最近的記錄將會保留在接口中以便用戶去從新啓動。接受該flag的activity可使用autoRemoveFromRecents去複寫這個request或者調用Activity.finishAndRemoveTask()方法。
FLAG_DEBUG_LOG_RESOLUTION 在處理這個intent的時候,將會打印相關建立日誌。
FLAG_RECEIVER_NO_ABORT 若是這是一個有序廣播,不容許接受者終止這個廣播,它仍然可以傳遞給下面的接受者。
FLAG_RECEIVER_REGISTERED_ONLY 若是設置了這個flag,當發送廣播的時,動態註冊的接受者纔會被調用,在AndroidManifest.xml裏定義的Receiver 是接收不到這樣的Intent的。
FLAG_RECEIVER_REPLACE_PENDING 若是設置了的話,ActivityManagerService就會在當前的系統中查看有沒有相同的intent還未被處理,若是有的話,就由當前這個新的intent來替換舊的intent,因此就會出如今發送一系列的這樣的 Intent 以後,中間有些 Intent 有可能在你尚未來得及處理的時候,就被替代掉了的狀況。
FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS 設置以後,廣播將對instant app中的廣播接收器可見。默認不可見。
FLAG_GRANT_READ_URI_PERMISSION 讀權限,容許組件從Intent中包含的URI裏邊讀取數據。
FLAG_GRANT_WRITE_URI_PERMISSION 寫權限,容許組件向Intent中包含的URI裏邊寫入數據。
FLAG_FROM_BACKGROUND 該Intent是一個後臺操做。

關於startActivityForResult()

由於 activity 的不少啓動模式或 flag 具備清除棧內已有 activity 的效果,清除實際是調用的系統的 remove task 方法,該方法會使得被清除的 activity 執行 onDestory() 等方法銷燬,同時若是被銷燬的 activity 是被其餘 activity 用startActivityForResult()方法啓動的,銷燬時會給它的啓動 activity 傳遞回去 result cancel 事件,啓動方 activity 的onActivityResult()方法會被調用,這個時候容易出現咱們意料以外的問題。

從 Task 的角度看,Android 認爲不一樣 Task 之間的 Activity 是不能傳遞數據的,所以若是啓動用startActivityForResult()方式啓動新 activity,而新啓動的 activity 和當前 activity 不在同一個棧時,當前 activity 的onActivityResult()方法回立刻被回調,而且傳遞迴result cancel事件,能夠從 AMS 打出的 log 上看到有這麼一句:

WARN/ActivityManager(67): Activity is launching as a new task, so cancelling activity result.

就是這個意思,下面startActivityForResult()的註釋也進行了說明。

3、數據傳遞

Intent傳遞數據

putExtra("key","value");
String str = getStringExtra(「key」);
複製代碼

Bundle傳遞數據

Bundle bundle = new Bundle();
bundle.putString("key","value");
intent.putExtras(bundle);
String str = getIntent().getExtras().getString("key");
複製代碼

4、Intent匹配規則

顯式啓動,直接用ComponentName定位到肯定的組件並啓動。
隱式啓動,與三個因素有關:CategoryActionDataExtrasFlag只在目標組件已經選擇好準備啓動時才起做用。這些因素中的一個組合就是一個intent-filter

隱士啓動匹配規則:至少有一個intent-filter匹配成功,才能啓動該組件。

幾個注意事項:

  1. Intent中若是不指定Category那麼系統會默認添加CATEGORY_DEFAULT
  2. 若是intent-filteraction爲空,那麼全部的Intent都不能與之匹配。
  3. 若是intent-filter中有非空action,那麼Intent中的action必須爲空,或是其子集才能與之匹配。
  4. Intentdata沒有指定MIME也沒有指定URI,此時只有intent-filter中也不指定相應值才能匹配。
  5. Intentdata沒有指定MIME(也沒法從URI推斷出來),但有指定URI,此時只有intent-filter中也不指定MIME,且URI符合要求,才能匹配。
  6. Intentdata指定了MIME,但沒有指定URI,此時只有intent-filter中也指定MIME且不指定URI,才能匹配。
  7. Intentdata指定了MIME,也指定了URI,此時只有intent-filter中也指定MIMEURI符合要求,才能匹配。

ComponentName

指定包名和全類名,直接定位到要啓動的組件。比如一我的的名字,能夠直接定位到這我的。

Category

從大的方向上對Intent進行了分類。比如國籍,能夠定位到這我的所在的國家,不能定位到這我的。
通常來講,CATEGORY_DEFAULT能夠解決全部問題,Intent默認指定的也是該值。

如下是標準Category。

Category Name Description
CATEGORY_DEFAULT 目標方對於默認的Action是一個可選項。
CATEGORY_BROWSABLE 目標方能正確顯示連接所指向的內容,如圖片、網頁等。可以被瀏覽器安全調用的組件必須制定該值。
CATEGORY_TAB 目標方能夠在已有的TabActivity內部做爲一個Tab使用。
CATEGORY_ALTERNATIVE 目標方是能正確打開用戶正在瀏覽的數據的一個選擇。
CATEGORY_SELECTED_ALTERNATIVE 目標方能正確打開用戶已經選擇的數據。
CATEGORY_LAUNCHER 目標方能夠經過點擊Launcher中的圖標來啓動。
CATEGORY_INFO 目標方用於提供包信息,當應用沒有CATEGORY_LAUNCHER組件時使用。
CATEGORY_HOME Launcher,系統啓動後啓動的第一個組件。
CATEGORY_PREFERENCE 該組件是選項卡
CATEGORY_TEST 測試使用(通常狀況不使用)
CATEGORY_CAR_DOCK 手機被插入汽車底座(硬件)時啓動目標方。
CATEGORY_DESK_DOCK 手機被插入桌面底座(硬件,櫃檯展現樣機)時啓動目標方。
CATEGORY_LE_DESK_DOCK
CATEGORY_HE_DESK_DOCK
CATEGORY_CAR_MODE 目標方可在車載環境下使用。
CATEGORY_APP_MARKET 用來指定目標方是應用市場。
CATEGORY_VR_HOME 目標方做爲VR啓動頁面。

如下Category,之後可能不兼容。

Category Name Description
CATEGORY_VOICE 目標方能與用戶進行語音交互,可能不須要UI展現。
CATEGORY_LEANBACK_LAUNCHER 目標方將在LEANBACK模式時啓動。leanback,指能夠像看電視同樣向後靠着看,形容清晰度高。
CATEGORY_CAR_LAUNCHER 目標方將在CAR_LAUNCHER模式時啓動。
CATEGORY_LEANBACK_SETTINGS 目標方將做爲LEANBACK模式中一個設置頁面。
CATEGORY_DEVELOPMENT_PREFERENCE 該組件是一個開發者選項卡。
CATEGORY_EMBED 能夠運行在父Activity容器內。
CATEGORY_MONKEY 目標方能夠被monkey或者其餘的自動測試工具執行。
CATEGORY_UNIT_TEST 單元測試使用。
CATEGORY_SAMPLE_CODE Sample組件
CATEGORY_OPENABLE 用來指示一個GET_CONTENT意圖但願只有ContentResolver.openInputStream可以打開URI。
CATEGORY_TYPED_OPENABLE 用來打開文件或流,使用openFileDescriptoropenTypedAssetFileDescriptorgetStreamTypes方法。
CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST 用於測試時,做爲framework層測試代碼使用。
CATEGORY_APP_BROWSER ACTION_MAIN一塊兒使用,用來指定目標方是瀏覽器應用。
CATEGORY_APP_CALCULATOR ACTION_MAIN一塊兒使用,用來指定目標方是計算器應用。
CATEGORY_APP_CALENDAR ACTION_MAIN一塊兒使用,用來指定目標方是日曆應用。
CATEGORY_APP_CONTACTS ACTION_MAIN一塊兒使用,用來指定目標方是聯繫人應用。
CATEGORY_APP_EMAIL ACTION_MAIN一塊兒使用,用來指定目標方是郵件應用。
CATEGORY_APP_GALLERY ACTION_MAIN一塊兒使用,用來指定目標方是圖庫應用。
CATEGORY_APP_MAPS ACTION_MAIN一塊兒使用,用來指定目標方是地圖應用。
CATEGORY_APP_MESSAGING ACTION_MAIN一塊兒使用,用來指定目標方是短信應用。
CATEGORY_APP_MUSIC ACTION_MAIN一塊兒使用,用來指定目標方是音樂應用。

Action

啓動Activity使用。

Action Description
ACTION_MAIN 應用程序入口。
ACTION_VIEW 顯示數據給用戶。
ACTION_ATTACH_DATA 指明附加信息。
ACTION_EDIT 顯示可編輯數據。
ACTION_PICK 顯示可選擇數據。
ACTION_CHOOSER 選擇器。
ACTION_GET_CONTENT 用於獲取信息。
ACTION_DIAL 顯示打電話面板。
ACTION_CALL 直接打電話。
ACTION_SEND 直接發短信。
ACTION_SENDTO 選擇聯繫人發短信。
ACTION_ANSWER 應答電話。
ACTION_INSERT 插入數據。
ACTION_DELETE 刪除數據。
ACTION_RUN 運行數據。
ACTION_SYNC 同步數據。
ACTION_PICK_ACTIVITY 選擇Activity。
ACTION_SEARCH 搜索。
ACTION_WEB_SEARCH Web搜索。
ACTION_FACTORY_TEST 工廠測試入口點。

系統廣播使用。

Action Description
ACTION_TIME_TICK 系統時間,1分鐘發一次廣播
ACTION_TIME_CHANGED 系統時間經過設置發生了變化。
ACTION_TIMEZONE_CHANGED 時區改變。
ACTION_BOOT_COMPLETED 系統啓動完畢。
ACTION_PACKAGE_ADDED 新的應用程序apk包安裝完畢。
ACTION_PACKAGE_CHANGED 現有應用程序apk包改變。
ACTION_PACKAGE_REMOVED 現有應用程序apk包被刪除。
ACTION_PACKAGE_RESTARTED 應用重啓。
ACTION_PACKAGE_DATA_CLEARED 應用數據被清理。
ACTION_PACKAGES_SUSPENDED 應用被掛起。
ACTION_PACKAGES_UNSUSPENDED 應用被解除掛起狀態,恢復正常。
ACTION_UID_REMOVED 用戶id被刪除。
ACTION_BATTERY_CHANGED 電池信息變化,包括電量變化。
ACTION_POWER_CONNECTED 外接電源,如充電寶。
ACTION_POWER_DISCONNECTED 外接電源拔出。
ACTION_SHUTDOWN 設備關機。

Data

data屬性有如下5部分組成:
android:scheme
android:host
android:port
android:path
android:mimeType

data的前四個屬性構成了URI(scheme://host:port/path),mimeType設置了數據的類型。

附:參考

官方文檔。 深刻理解Android內核設計思想.林學森 SDK源碼。

相關文章
相關標籤/搜索