目錄
- 1.Activity
- 2.Service
- 3.BroadcastReceiver
- 4.ContentProvider
- 5.Handler
- 6.View繪制
- 7.View事件分發
- 8.RecycleView
- 9.Viewpager&Fragment
- 10.Webview
- 11.影片
- 12.Bitmap
- 13.mvc&mvp&mvvm
- 14.Binder
- 15.記憶體泄漏&記憶體溢位
- 16.性能優化
- 17.Window&WindowManager
- 18.AMS
- 19.系統啟動
- 20.App啟動&打包&安裝
- 21.序列化
- 22.Art & Dalvik及其區別
- 23.模塊化&組件化
- 24.熱修復&插件化
- 25.AOP
- 26.jectpack
- 27.開源框架
1.Activity
1.1.Activity的啟動流程
Activity跨行程啟動
啟動流程:
點擊桌面App圖示,Launcher行程采用Binder IPC向system_server行程發起startActivity請求;
system_server行程接收到請求后,向zygote行程發送創建行程的請求;
Zygote行程fork出新的子行程,即App行程;
App行程,通過Binder IPC向sytem_server行程發起attachApplication請求;
system_server行程在收到請求后,進行一系列準備作業后,再通過binder IPC向App進 程發送scheduleLaunchActivity請求;
App行程的binder執行緒(ApplicationThread)在收到請求后,通過handler向主執行緒發送LAUNCH_ACTIVITY訊息;
主執行緒在收到Message后,通過發射機制創建目標Activity,并回呼Activity.onCreate()等方法,
Activity行程內啟動
請求行程A:startActivity—(hook插入點1) (AMP,ActivityManager代理物件)——> system_server行程:AMS(ActivityManagerService)
決議Activity資訊、處理啟動引數、scheduleLaunchActivity/mH中EXECUTE_TRANSACTION訊息處理(Android P)–>
回到請求行程A:ApplicationThread --> ActivityThread -(hook插入點2)-> Activity生命周期

()
1.2.onSaveInstanceState(),onRestoreInstanceState的掉用時機
1.2.1onSaveInstanceState(Bundle outState)會在以下情況被呼叫:
1.2.1.1、從最近應用中選擇運行其他的程式時,
1.2.1.2、當用戶按下HOME鍵時,
1.2.1.3、螢屏方向切換時(無論豎屏切橫屏還是橫屏切豎屏都會呼叫),
1.2.1.4、按下電源按鍵(關閉螢屏顯示)時,
1.2.1.5、從當前activity啟動一個新的activity時,
onPause -> onSaveInstanceState -> onStop,
1.2.2onRestoreInstanceState(Bundle outState)會在以下情況被呼叫:
onRestoreInstanceState(Bundle savedInstanceState)只有在activity確實是被系統回收,重新創建activity的情況下才會被呼叫,
1.2.2.1.螢屏方向切換時,activity生命周期如下
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
1.2.2.2.在后臺被回收
1.2.2.3.按HOME鍵回傳桌面,又馬上點擊應用圖示回到原來頁面時不會被回收
onStart -> onRestoreInstanceState -> onResume
1.2.3原始碼
系統會呼叫ActivityThread的performStopActivity方法中掉用onSaveInstanceState, 將狀態保存在mActivities中,mActivities維護了一個Activity的資訊表,當Activity重啟時候,會從mActivities中查詢到對應的ActivityClientRecord,
如果有資訊,則呼叫Activity的onResoreInstanceState方法,
在ActivityThread的performLaunchActivity方法中,統會判斷ActivityClientRecord物件的state是否為空
不為空則通過Activity的onSaveInstanceState獲取其UI狀態資訊,通過這些資訊傳遞給Activity的onCreate方法,
1.3.activity的啟動模式和使用場景
1.3.1 android任務堆疊
我們每次打開一個新的Activity或者退出當前Activity都會在一個稱為任務堆疊的結構中添加或者減少一個Activity組件,一個任務堆疊包含了一個activity的集合,
android通過ActivityRecord、TaskRecord、ActivityStack,ActivityStackSupervisor,ProcessRecord有序地管理每個activity,
1.3.2 Standard
默認模式,每次啟動Activity都會創建一個新的Activity實體,
1.3.3 SingleTop
通知訊息打開的頁面
如果要啟動的Activity已經在堆疊頂,則不會重新創建Activity,只會呼叫該該Activity的onNewIntent()方法,
如果要啟動的Activity不在堆疊頂,則會重新創建該Activity的實體,
1.3.4 SingleTask
主界面
如果要啟動的Activity已經存在于它想要歸屬的堆疊中,那么不會創建該Activity實體,將堆疊中位于該Activity上的所有的Activity出堆疊,同時該Activity的onNewIntent()方法會被呼叫,
1.3.5SingleInstance
呼叫來電界面
要創建在一個新堆疊,然后創建該Activity實體并壓入新堆疊中,新堆疊中只會存在這一個Activity實體,
1.4.Activity A跳轉Activity B,再按回傳鍵,生命周期執行的順序
在A跳轉B會執行:A onPause -> B onCreate -> B onStart -> B onResume->A onStop
在B按下回傳鍵會執行:B onPause -> A onRestart -> A onStart -> A onResume-> B onStop -> B onDestroy
當A跳轉到B的時候,A先執行onPause,然后居然是B再執行onCreate -> onStart -> onResume,最后才執行A的onStop!!!
當B按下回傳鍵,B先執行onPause,然后居然是A再執行onRestart -> onStart -> onResume,最后才是B執行onStop -> onDestroy!!!
當 B Activity 的 launchMode 為 singleInstance,singleTask 且對應的 B Activity 有可復用的實體時,生命周期回呼是這樣的:
A.onPause -> B.onNewIntent -> B.onRestart -> B.onStart -> B.onResume -> A.onStop -> ( 如果 A 被移出堆疊的話還有一個 A.onDestory)
當 B Activity 的 launchMode 為 singleTop且 B Activity 已經在堆疊頂時(一些特殊情況如通知欄點擊、連點),此時只有 B 頁面自己有生命周期變化:
B.onPause -> B.onNewIntent -> B.onResume
1.5.橫豎屏切換,按home鍵,按回傳鍵,鎖屏與解鎖螢屏,跳轉透明Activity界面,啟動一個 Theme 為 Dialog 的 Activity,彈出Dialog時Activity的生命周期
橫豎屏切換:
從 Android 3.2 (API級別 13)開始
1、不設定Activity的androidconfigChanges,或設定Activity的androidconfigChanges=“orientation”,或設定Activity的android:configChanges=“orientation|keyboardHidden”,切屏會重新呼叫各個生命周期,切橫屏時會執行一次,切豎屏時會執行一次,
2、配置 android:configChanges=“orientation|keyboardHidden|screenSize”,才不會銷毀 activity,且只呼叫 onConfigurationChanged方法,
豎屏:
啟動:onCreat->onStart->onResume.
切換橫屏時:
onPause-> onSaveInstanceState ->onStop->onDestory
onCreat->onStart->onSaveInstanceState->onResume.
如果配置這個屬性:androidconfigChanges=“orientation|keyboardHidden|screenSize”
就不會在呼叫Activity的生命周期,只會呼叫onConfigurationChanged方法
HOME鍵的執行順序:onPause->onStop->onRestart->onStart->onResume
BACK鍵的順序: onPause->onStop->onDestroy->onCreate->onStart->onResume
鎖屏:鎖屏時只會呼叫onPause(),而不會呼叫onStop方法,開屏后則呼叫onResume(),
彈出 Dialog: 直接是通過 WindowManager.addView 顯示的(沒有經過 AMS),所以不會對生命周期有任何影響,
啟動theme為DialogActivity,跳轉透明Activity
A.onPause -> B.onCrete -> B.onStart -> B.onResume
( Activity 不會回呼 onStop,因為只有在 Activity 切到后臺不可見才會回呼 onStop)
1.6.onStart 和 onResume、onPause 和 onStop 的區別
onStart 和 onResume 從 Activity 可見可互動區分
onStart 用戶可以看到部分activity但不能與它互動 onResume()可以獲得activity的焦點,能夠與用戶互動
onStop 和 onPause 從 Activity 是否位于前臺,是否有焦點區分
onPause表示當前頁面失去焦點,
onStop表示當前頁面不可見,
dialog的主題頁面,這個時候,打開著一個頁面,就只會執行onPause,而不會執行onStop,
1.7.Activity之間傳遞資料的方式Intent是否有大小限制,如果傳遞的資料量偏大,有哪些方案
startActivity->startActivityForResult->Instrumentation.execStartActivity
->ActivityManger.getService().startActivity
intent中攜帶的資料要從APP行程傳輸到AMS行程,再由AMS行程傳輸到目標Activity所在行程
通過Binder來實作行程間通信
1.Binder 驅動在內核空間創建一個資料接收快取區,
2.在內核空間開辟一塊內核快取區,建立內核快取區和內核空間的資料接收快取區之間的映射關系,以及內核中資料接收快取區和接收行程用戶空間地址的映射關系,
3.發送方行程通過系統呼叫 copyfromuser() 將資料 copy 到內核空間的內核快取區,由于內核快取區和接收行程的用戶空間存在記憶體映射,因此也就相當于把資料發送到了接收行程的用戶空間,這樣便完成了一次行程間的通信,
為當使用Intent來傳遞資料時,用到了Binder機制,資料就存放在了Binder的事務緩沖區里面,而事務緩沖區是有大小限制的,普通的由Zygote范訓而來的用戶行程,映射的Binder記憶體大小是不到1M的
Binder 本身就是為了行程間頻繁-靈活的通信所設計的, 并不是為了拷貝大量資料
如果非 ipc
單例,eventBus,Application,sqlite、shared preference、file 都可以;
如果是 ipc
1.共享記憶體性能還不錯, 通過 MemoryFile 開辟記憶體空間,獲得 FileDescriptor; 將 FileDescriptor 傳遞給其他行程; 往共享記憶體寫入資料; 從共享記憶體讀取資料,
2.Socket或者管道性能不太好,涉及到至少兩次拷貝,
1.8.Activity的onNewIntent()方法什么時候執行
果IntentActivity處于任務堆疊的頂端,也就是說之前打開過的Activity,現在處于onPause、onStop 狀態的話,其他應用再發送Intent的話,執行順序為:onNewIntent,onRestart,onStart,onResume,
ActivityA已經啟動過,處于當前應用的Activity堆疊中;
當ActivityA的LaunchMode為SingleTop時,如果ActivityA在堆疊頂,且現在要再啟動ActivityA,這時會呼叫onNewIntent()方法;
當ActivityA的LaunchMode為SingleInstance,SingleTask時,如果已經ActivityA已經在堆疊中,那么此時再次啟動會呼叫onNewIntent()方法;
1.9.顯示啟動和隱式啟動
顯示啟動
1、構造方法傳入Component,最常用的方式
2、setComponent(componentName)方法
3、setClass/setClassName方法
隱式啟動
隱式Intent是通過在AndroidManifest檔案中設定action、data、category,讓系統來篩選出合適的Activity
action的匹配規則
Intent-filter action可以設定多條
intent中的action只要與intent-filter其中的一條匹配成功即可,且intent中action最多只有一條
Intent-filter內必須至少包含一個action,
category的匹配規則
Intent-filter內必須至少包含一個category,android:name為android.intent.category.DEFAULT,
intent-filter中,category可以有多條
intent中,category也可以有多條
intent中所有的category都可以在intent-filter中找到一樣的(包括大小寫)才算匹配成功
data的匹配規則
intent-filter中可以設定多個data
intent中只能設定一個data
intent-filter中指定了data,intent中就要指定其中的一個data
1.10.scheme使用場景,協議格式,如何使用
scheme是一種頁面內跳轉協議,是一種非常好的實作機制,通過定義自己的scheme協議,可以非常方便跳轉app中的各個頁面
APP根據URL跳轉到另外一個APP指定頁面
可以通過h5頁面跳轉app原生頁面
服務器可以定制化跳轉app頁面
Scheme鏈接格式樣式
樣式scheme://host/path?query
Uri.parse(“hr://test:8080/goods?goodsId=8897&name=test”)
hr代表Scheme協議名稱
test代表Scheme作用的地址域
8080代表改路徑的埠號
/goods代表的是指定頁面(路徑)
goodsId和name代表傳遞的兩個引數
使用
<intent-filter>
<!-- 協議部分配置 ,注意需要跟web配置相同-->
<!--協議部分,隨便設定 hr://test:8080/goods?name=test -->
<data android:scheme="hr"
android:host="test"
android:path="/goods"
android:port="8080"/>
<!--下面這幾行也必須得設定-->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<action android:name="android.intent.action.VIEW" />
</intent-filter>
掉用
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("hr://test:8080/goods?name=test"));
startActivity(intent);
1.11.ANR 的四種場景
ANR 的四種場景:
Service TimeOut: service 未在規定時間執行完成:前臺服務 20s,后臺 200s
BroadCastQueue TimeOut: 未在規定時間內未處理完廣播:前臺廣播 10s 內, 后臺 60s 內
ContentProvider TimeOut: publish 在 10s 內沒有完成
Input Dispatching timeout: 5s 內未回應鍵盤輸入、觸摸螢屏等事件
我們可以看到, Activity 的生命周期回呼的阻塞并不在觸發 ANR 的場景里面,所以并不會直接觸發 ANR,
只不過死回圈阻塞了主執行緒,如果系統再有上述的四種事件發生,就無法在相應的時間內處理從而觸發 ANR,
1.12.onCreate和onRestoreInstance方法中恢復資料時的區別
onSaveInstanceState 不一定會被呼叫,因為它只有在上次activity被回收了才會呼叫,
onCreate()里的Bundle引數可能為空,一定要做非空判斷, 而onRestoreInstanceState的Bundle引數一定不會是空值,
1.13.activty間傳遞資料的方式
通過 Intent 傳遞(Intent.putExtra 的內部也是維護的一個 Bundle,因此,通過 putExtra 放入的 資料,取出時也可以通過 Bundle 去取)
通過全域變數傳遞
通過 SharedPreferences 傳遞
通過資料庫傳遞
通過檔案傳遞
1.14.跨App啟動Activity的方式,注意事項
使用intentFilter(隱式跳轉)
在Manifest的Activity標簽中添加:
啟動時:startActivity(new Intent(“com.example.test.action.BActivity”))
如果有兩個action屬性值相同的Activity,那么在啟動時手機系統會讓你選擇啟動哪一個Activity
要解決這個問題,需要給被啟動的Activity再加上一個屬性,
然后再啟動該Activity的Intent中加上一個URI,其中“app”必須與data屬性的scheme的值一樣,
intent=new Intent(“com.zs.appb.intent.action.BeStartActivity”, Uri.parse(“app://hello”));
共享uid的App
android中uid用于標識一個應用程式,uid在應用安裝時被分配,并且在應用存在于手機上期間,都不會改變,一個應用程式只能有一個uid,多個應用可以使用sharedUserId 方式共享同一個uid,前提是這些應用的簽名要相同,
在AndroidManifest中:manifest標簽中添加android:sharedUserId=“xxxx”
啟動時:startActivity(new Intent().setComponent(new ComponentName(“com.example.test”,“com.example.test.XxxActivity”)));
使用exported
一旦設定了intentFilter之后,exported就默認被設定為true了
在Manifest中添加exported屬性
啟動時:startActivity(new Intent().setComponent(new ComponentName(“com.example.zhu”,“com.example.zhu.XxxActivity”)));
注意(如何防止自己的Activity被外部非正常啟動):
如果AppB設定了android:permission=”xxx.xxx.xx”那么, 就必須在你的AppA的AndroidManifast.xml中uses-permission xxx.xxx.xx才能訪問人家的東西,
給AppA的manifest中添加權限:
gei AppB中需要啟動的Activity添加permission屬性:
android:permission=“com.example.test”
1.15.Activity任務堆疊是什么
1.android任務堆疊又稱為Task,它是一個堆疊結構,具有后進先出的特性,用于存放我們的Activity組件,
2.我們每次打開一個新的Activity或者退出當前Activity都會在一個稱為任務堆疊的結構中添加或者減少一個Activity組件, 一個任務堆疊包含了一個activity的集合, 只有在任務堆疊堆疊頂的activity才可以跟用戶進行互動,
3.在我們退出應用程式時,必須把所有的任務堆疊中所有的activity清除出堆疊時,任務堆疊才會被銷毀,當然任務堆疊也可以移動到后臺, 并且保留了每一個activity的狀態. 可以有序的給用戶列出它們的任務, 同時也不會丟失Activity的狀態資訊,
4.對應AMS中的ActivityRecord、TaskRecord、ActivityStack(AMS中的總結)
1.16.有哪些Activity常用的標記位Flags
FLAG_ACTIVITY_NEW_TASK
此標記位作用是為Activity指定“singleTask”啟動模式,其效果和在XML中指定相同android:launchMode=“singleTask”
FLAG_ACTIVITY_SINGLE_TOP
此標記位作用是為Activity指定“singleTop”啟動模式,其效果和在XML中指定相同android:launchMode=“singleTop”
FLAG_ACTIVITY_CLEAR_TOP
具有此標記位的Activity,當它啟動時,在同一個任務堆疊中位于它上面的Activity都要出堆疊,此標記位一般會和singleTask啟動模式一起出現,此情況下,若被啟動的Activity實體存在,則系統會呼叫它的onNewIntent,
1.17.Activity的資料是怎么保存的,行程被Kill后,保存的資料怎么恢復的
在Activity的onSaveInstanceState方法回呼時,put到引數outState(Bundle)里面,outState就是ActivityClientRecord的state,
ActivityClientRecord實體,都存放在ActivityThread的mActivities里面,
Activity變得不可見時(onSaveInstanceState和onStop回呼之后),在應用行程這邊會通過ActivityTaskManagerService的activityStopped方法,把剛剛在onSaveInstanceState中滿載了資料的Bundle物件,傳到系統服務行程那邊! 然后(在系統服務行程這邊),會進一步將這個Bundle物件,賦值到對應ActivityRecord的icicle上
ActivityRecord是用來記錄對應Activity的各種資訊的,如theme,啟動模式、當前是否可見等等(為了排版更簡潔,上圖只列出來一個icicle),它里面還有很多管理Activity狀態的相關方法;
TaskRecord就是大家耳熟能詳的任務堆疊(從上圖可以看出并不真的是堆疊)了,它的主要職責就是管理ActivityRecord,每當Activity啟動時,會先找到合適的TaskRecord(或創建新實體),然后將該Activity所對應的ActivityRecord添加到TaskRecord的mActivities中;
ActivityStack管理著TaskRecord,當新TaskRecord被創建后,會被添加到它mTaskHistory里面,
2.Service
2.1.service 的生命周期,兩種啟動方式的區別
startService
onCreate() -> onStartCommand() -> onDestroy()
bindService
onCreate() -> onbind() -> onUnbind()-> onDestroy()
區別
啟動
如果服務已經開啟,多次執行startService不會重復的執行onCreate(), 而是會呼叫onStart()和onStartCommand(),
如果服務已經開啟,多次執行bindService時,onCreate和onBind方法并不會被多次呼叫
銷毀
當執行stopService時,直接呼叫onDestroy方法
呼叫者呼叫unbindService方法或者呼叫者Context不存在了(如Activity被finish了),Service就會呼叫onUnbind->onDestroy
使用startService()方法啟用服務,呼叫者與服務之間沒有關連,即使呼叫者退出了,服 務仍然運行,
使用bindService()方法啟用服務,呼叫者與服務系結在了一起,呼叫者一旦退出,服務也就終止,
1、單獨使用startService & stopService
(1)第一次呼叫startService會執行onCreate、onStartCommand,
(2)之后再多次呼叫startService只執行onStartCommand,不再執行onCreate,
(3)呼叫stopService會執行onDestroy,
2、單獨使用bindService & unbindService
(1)第一次呼叫bindService會執行onCreate、onBind,
(2)之后再多次呼叫bindService不會再執行onCreate和onBind,
(3)呼叫unbindService會執行onUnbind、onDestroy,
2.2.Service啟動流程

1.Process A行程采用Binder IPC向system_server行程發起startService請求;
2.system_server行程接收到請求后,向zygote行程發送創建行程的請求;
3.zygote行程fork出新的子行程Remote Service行程;
4.Remote Service行程,通過Binder IPC向sytem_server行程發起attachApplication請求;
5.system_server行程在收到請求后,進行一系列準備作業后,再通過binder IPC向remote Service行程發送scheduleCreateService請求;
6.Remote Service行程的binder執行緒在收到請求后,通過handler向主執行緒發送CREATE_SERVICE訊息;
7.主執行緒在收到Message后,通過發射機制創建目標Service,并回呼Service.onCreate()方法,
到此,服務便正式啟動完成,當創建的是本地服務或者服務所屬行程已創建時,則無需經過上述步驟2、3,直接創建服務即可,
bindService

startService

2.3.Service與Activity怎么實作通信
通過Binder物件
1.Service中添加一個繼承Binder的內部類,并添加相應的邏輯方法
2.Service中重寫Service的onBind方法,回傳我們剛剛定義的那個內部類實體
3.Activity中系結服務,重寫ServiceConnection,onServiceConnected時回傳的IBinder(Service中的binder)呼叫邏輯方法
Service通過BroadCast廣播與Activity通信
2.4.IntentService是什么,IntentService原理,應用場景及其與Service的區別
what
IntentService 是 Service 的子類,默認開啟了一個作業執行緒HandlerThread,使用這個作業執行緒逐一處理所有啟動請求,在任務執行完畢后會自動停止服務,只要實作一個方法 onHandleIntent,該方法會接收每個啟動請求的 Intent,能夠執行后臺作業和耗時操作,
可以啟動 IntentService 多次,而每一個耗時操作會以佇列的方式在 IntentService 的 onHandlerIntent 回呼方法中執行,并且,每一次只會執行一個作業執行緒,執行完第一個再執行第二個,并且等待所有訊息都執行完后才終止服務,
how
1.創建一個名叫 ServiceHandler 的內部 Handler
2.把內部Handler與HandlerThread所對應的子執行緒進行系結
3.HandlerThread開啟執行緒 創建自己的looper
4.通過 onStartCommand() intent,依次插入到作業佇列中,并發送給 onHandleIntent()逐個處理
可以用作后臺下載任務 靜默上傳
why IntentService會創建獨立的worker執行緒來處理所有的Intent請求 Service主執行緒不能處理耗時操作,IntentService不會阻塞UI執行緒,而普通Serveice會導致ANR例外,
為Service的onBind()提供默認實作,回傳null;onStartCommand提供默認實作,將請求Intent添加到佇列中,
所有請求處理完成后,IntentService會自動停止,無需呼叫stopSelf()方法停止Service,
2.5.Service 的 onStartCommand 方法有幾種回傳值?各代表什么意思?
START_NOT_STICKY
在執行完 onStartCommand 后,服務被例外 kill 掉,系統不會自動重啟該服務,
START_STICKY
重傳 Intent,使用這個回傳值時,如果在執行完 onStartCommand 后,服務被異 常 kill 掉,系統會自動重啟該服務 ,并且onStartCommand方法會執行,onStartCommand方法中的intent值為null,
適用于媒體播放器或類似服務,
START_REDELIVER_INTEN
使用這個回傳值時,服務被異 常 kill 掉,系統會自動重啟該服務,并將 Intent 的值傳入,
適用于主動執行應該立即恢復的作業(例如下載檔案)的服務,
2.6.bindService和startService混合使用的生命周期以及怎么關閉
如果你只是想要啟動一個后臺服務長期進行某項任務,那么使用startService便可以了,如果你還想要與正在運行的Service取得聯系,那么有兩種方法:一種是使用broadcast,另一種是使用bindService,
如果先startService,再bindService
onCreate() -> onbind() -> onStartCommand()
如果先bindService,再startService
onCreate() -> onStartCommand() -> onbind()
如果只stopService
Service的OnDestroy()方法不會立即執行,在Activity退出的時候,會執行OnDestroy,
如果只unbindService
只有onUnbind方法會執行,onDestory不會執行
如果要完全退出Service,那么就得執行unbindService()以及stopService,
3.BroadcastReceiver
3.1.廣播的分類和使用場景
Android 廣播分為兩個角色:廣播發送者、廣播接受者
廣播接收器的注冊分為兩種:靜態注冊、動態注冊,
靜態廣播接收者:通過AndroidManifest.xml的標簽來申明的BroadcastReceiver,
動態廣播接收者:通過AMS.registerReceiver()方式注冊的BroadcastReceiver,動態注冊更為靈活,可在不需要時通過unregisterReceiver()取消注冊,
廣播型別:根據廣播的發送方式,
1.普通廣播:通過Context.sendBroadcast()發送,可并行處理
2.系統廣播:當使用系統廣播時,只需在注冊廣播接收者時定義相關的action即可,不需要手動發送廣播(網路變化,鎖屏,飛行模式)
3.有序廣播: 指的是發送出去的廣播被 BroadcastReceiver 按照先后順序進行接收 發送方式變為:sendOrderedBroadcast(intent);
廣播接受者接收廣播的順序規則(同時面向靜態和動態注冊的廣播接受者):按照 Priority 屬性值從大-小排序,Priority屬性相同者,動態注冊的廣播優先,
4.App應用內廣播(Local Broadcast)
背景 Android中的廣播可以跨App直接通信(exported對于有intent-filter情況下默認值為true)
沖突 可能出現的問題:
其他App針對性發出與當前App intent-filter相匹配的廣播,由此導致當前App不斷接收廣播并處理;
其他App注冊與當前App一致的intent-filter用于接收廣播,獲取廣播具體資訊; 即會出現安全性 & 效率性的問題,
解決方案 使用App應用內廣播(Local Broadcast)
App應用內廣播可理解為一種區域廣播,廣播的發送者和接收者都同屬于一個App, 相比于全域廣播(普通廣播),App應用內廣播優勢體現在:安全性高 & 效率高
具體使用1 - 將全域廣播設定成區域廣播
注冊廣播時將exported屬性設定為false,使得非本App內部發出的此廣播不被接收; 在廣播發送和接收時,增設相應權限permission,用于權限驗證;
發送廣播時指定該廣播接收器所在的包名,此廣播將只會發送到此包中的App內與之相匹配的有效廣播接收器中,
具體使用2 - 使用封裝好的LocalBroadcastManager類
對于LocalBroadcastManage,方式發送的應用內廣播,只能通過LocalBroadcastManager動態注冊,不能靜態注冊
5.粘性廣播(Sticky Broadcast) 由于在Android5.0 & API 21中已經失效,所以不建議使用,在這里也不作過多的總結,
應用場景
同一 App 內部的不同組件之間的訊息通信(單個行程);
不同 App 之間的組件之間訊息通信;
Android系統在特定情況下與App之間的訊息通信,如:網路變化、電池電量、螢屏開關等,
3.2.廣播的兩種注冊方式的區別
靜態注冊:常駐系統,不受組件生命周期影響,即便應用退出,廣播還是可以被接收,耗電、占記憶體,
動態注冊:非常駐,跟隨組件的生命變化,組件結束,廣播結束,在組件結束前,需要先移除廣播,否則容易造成記憶體泄漏,
3.3.廣播發送和接收的原理
動態注冊
1.創建物件LoadedApk.ReceiverDispatcher.InnerReceiver的實體,該物件繼承于IIntentReceiver.Stub(InnerReceiver實際是一個binder本地物件(BBinder:本地Binder,服務實作方的基類,提供了onTransact介面來接收請求)),
2.將IIntentReceiver物件和注冊所傳的IntentFilter物件發送給AMS, AMS記錄IIntentReceiver、IntentFilter和注冊的行程ProcessRecord,并建立起它們的對應關系,
3.當有廣播發出時,AMS根據廣播intent所攜帶的IntentFilter找到IIntentReceiver和ProcessRecord,然后回呼App的ApplicationThread物件的scheduleRegisteredReceiver,將IIntentReceiver和廣播的intent一并傳給App,App直接呼叫IIntentReceiver的performReceive,
4.因為廣播是通過binder執行緒回呼到接收行程的,接收行程通過ActivityThread里的H這個Handler將呼叫轉到主執行緒,然后回呼BroadcastReceiver的onReceive,
靜態注冊
靜態注冊是通過在Manifest檔案中宣告實作了BroadcastReceiver的自定義類和對應的IntentFilter,來告訴PMS(PackageManagerService)這個App所注冊的廣播,
當AMS接收到廣播后,會查找所有動態注冊的和靜態注冊的廣播接收器,靜態注冊的廣播接收器是通過PMS(PackageManagerService)發現的,PMS找到對應的App
對應行程已經創建,直接呼叫App的ApplicationThread物件的scheduleReceiver
對應行程尚未創建,先啟動App行程,App行程啟動后回呼AMS的attachApplication,attachApplication則繼續派發剛才的廣播App這邊收到呼叫后會先通過Handler轉到主執行緒,然后根據AMS傳過來的引數實體化廣播接收器的類,接著呼叫廣播接收器的onReceive,
3.4.本地廣播和全域廣播的區別
BroadcastReceiver是針對應用間、應用與系統間、應用內部進行通信的一種方式
LocalBroadcastReceiver僅在自己的應用內發送接收廣播,也就是只有自己的應用能收到,資料更加安全廣播只在這個程式里,而且效率更高,
BroadcastReceiver采用的binder方式實作跨行程間的通信;
LocalBroadcastManager使用Handler通信機制,
LocalBroadcastReceiver 使用
LocalBroadcastReceiver不能靜態注冊,只能采用動態注冊的方式,
在發送和注冊的時候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法
注冊程序,主要是向mReceivers和mActions添加相應資料:
mReceivers:資料型別為HashMap<BroadcastReceiver, ArrayList>, 記錄廣播接收者與IntentFilter串列的對應關系;
mActions:資料型別為HashMap<String, ArrayList>, 記錄action與廣播接收者的對應關系
根據Intent的action來查詢相應的廣播接收者串列;
發送MSG_EXEC_PENDING_BROADCASTS訊息,回呼相應廣播接收者的onReceive方法

由于內容實在太多了,在這里就不方便做全部的展示,以上就是《Android高級開發面試題2.0》的部分,需要的小伙伴可以一鍵三連(點贊+收藏+關注)后直接+加V:lx5888888888838 或者【點擊這里直達免費獲取方式!】
寫在最后
我個人覺得面試也像是一場全新的征程,失敗和勝利都是平常之事,所以,勸各位不要因為面試失敗而灰心、喪失斗志,也不要因為面試通過而沾沾自喜,等待你的將是更美好的未來,繼續加油!
—————祝各位前程似錦,offer不斷!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292385.html
標籤:其他
