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
onCreate()
~ onDestroy()
onStart()
~ onStop()
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);
複製代碼
Activity A 的 onPause() 方法執行。
Activity B 的 onCreate()、onStart() 和 onResume() 方法依次執行。(Activity B 如今具備用戶焦點。)
而後,若是 Activity A 在屏幕上再也不可見,則其 onStop() 方法執行。
Launcher
組件向ActivityManagerService
發送一個啓動MainActivity
的進程間通訊請求。ActivityManagerService
首先將要啓動的MainActivity
信息保存起來,而後再向Launcher發送一個進入終止狀態的進程間通訊請求。Launcher
組件進入終止狀態後就會向ActivityManagerService
發送一個已經進入終止狀態的進程間通訊請求,以便ActivityManagerService
能夠繼續執行MainActivity
的啓動。ActivityManagerService
發現用於運行MainActivity
的應用程序進程不存在,所以會先啓動一個新的應用程序進程。ActivityManagerService
發送一個啓動完成的進程間通訊請求,以便ActivityManagerService
能夠繼續執行MainActivity
的啓動。ActivityManagerService
將第二步保存起來的MainActivity
信息發送第四步建立的新的應用程序進程,以便將MainActivity
啓動起來。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 | 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()
的註釋也進行了說明。
putExtra("key","value");
String str = getStringExtra(「key」);
複製代碼
Bundle bundle = new Bundle();
bundle.putString("key","value");
intent.putExtras(bundle);
String str = getIntent().getExtras().getString("key");
複製代碼
顯式啓動,直接用ComponentName
定位到肯定的組件並啓動。
隱式啓動,與三個因素有關:Category
、Action
、Data
。Extras
和Flag
只在目標組件已經選擇好準備啓動時才起做用。這些因素中的一個組合就是一個intent-filter
。
隱士啓動匹配規則:至少有一個intent-filter
匹配成功,才能啓動該組件。
幾個注意事項:
Intent
中若是不指定Category
那麼系統會默認添加CATEGORY_DEFAULT
。intent-filter
中action
爲空,那麼全部的Intent
都不能與之匹配。intent-filter
中有非空action
,那麼Intent
中的action
必須爲空,或是其子集才能與之匹配。Intent
的data
沒有指定MIME
也沒有指定URI
,此時只有intent-filter
中也不指定相應值才能匹配。Intent
的data
沒有指定MIME
(也沒法從URI推斷出來),但有指定URI
,此時只有intent-filter
中也不指定MIME
,且URI
符合要求,才能匹配。Intent
的data
指定了MIME
,但沒有指定URI
,此時只有intent-filter
中也指定MIME
且不指定URI
,才能匹配。Intent
的data
指定了MIME
,也指定了URI
,此時只有intent-filter
中也指定MIME
且URI
符合要求,才能匹配。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 |
用來打開文件或流,使用openFileDescriptor 、openTypedAssetFileDescriptor 、getStreamTypes 方法。 |
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 一塊兒使用,用來指定目標方是音樂應用。 |
啓動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屬性有如下5部分組成:
android:scheme
android:host
android:port
android:path
android:mimeType
data的前四個屬性構成了URI(scheme://host:port/path
),mimeType設置了數據的類型。
官方文檔。 深刻理解Android內核設計思想.林學森 SDK源碼。