1.1 Activity 與 Fragment 之間常見(jiàn)的幾種通信方式?
viewModel 做數(shù)據(jù)管理,activity 和 fragment 公用同個(gè)viewModel 實(shí)現(xiàn)數(shù)據(jù)傳遞
1.2 LaunchMode 的應(yīng)用場(chǎng)景?
LaunchMode 有四種,分別為 Standard,SingleTop,SingleTask 和 SingleInstance,每種模式的實(shí)現(xiàn)原理一樓都做了較詳細(xì)說(shuō)明,下面說(shuō)一下具體使用場(chǎng)景:
Standard
Standard 模式是系統(tǒng)默認(rèn)的啟動(dòng)模式,一般我們 app中大部分頁(yè)面都是由該模式的頁(yè)面構(gòu)成的,比較常見(jiàn)的場(chǎng)景是:社交應(yīng)用中,點(diǎn)擊查看用戶(hù)A信息->查看用戶(hù)A粉絲->在粉絲中挑選查看用戶(hù)B信息->查看用戶(hù)A粉絲...
這種情況下一般我們需要保留用戶(hù)操作 Activity 棧的頁(yè)面所有執(zhí)行順序。SingleTop
SingleTop 模式一般常見(jiàn)于社交應(yīng)用中的通知欄行為功能,例如:App 用戶(hù)收到幾條好友請(qǐng)求的推送消息,需要用戶(hù)點(diǎn)擊推送通知進(jìn)入到請(qǐng)求者個(gè)人信息頁(yè),將信息頁(yè)設(shè)置為 SingleTop 模式就可以增強(qiáng)復(fù)用性。SingleTask
SingleTask 模式一般用作應(yīng)用的首頁(yè),例如瀏覽器主頁(yè),用戶(hù)可能從多個(gè)應(yīng)用啟動(dòng)瀏覽器,但主界面僅僅啟動(dòng)一次,其余情況都會(huì)走onNewIntent,并且會(huì)清空主界面上面的其他頁(yè)面。SingleInstance
SingleInstance 模式常應(yīng)用于獨(dú)立棧操作的應(yīng)用,如鬧鐘的提醒頁(yè)面,當(dāng)你在A應(yīng)用中看視頻時(shí),鬧鐘響了,你點(diǎn)擊鬧鐘提醒通知后進(jìn)入提醒詳情頁(yè)面,然后點(diǎn)擊返回就再次回到A的視頻頁(yè)面,這樣就不會(huì)過(guò)多干擾到用戶(hù)先前的操作了。
1.3 BroadcastReceiver 與 LocalBroadcastReceiver 有什么區(qū)別?
BroadcastReceiver 是跨應(yīng)用廣播,利用Binder機(jī)制實(shí)現(xiàn),支持動(dòng)態(tài)和靜態(tài)兩種方式注冊(cè)方式。
LocalBroadcastReceiver 是應(yīng)用內(nèi)廣播,利用Handler實(shí)現(xiàn),利用了IntentFilter的match功能,提供消息的發(fā)布與接收功能,實(shí)現(xiàn)應(yīng)用內(nèi)通信,效率和安全性比較高,僅支持動(dòng)態(tài)注冊(cè)。
1.4 對(duì)于 Context,你了解多少?
Context 也叫上下文,是有關(guān)應(yīng)用程序環(huán)境的全局信息的接口。這是一個(gè)抽象類(lèi), 它允許訪問(wèn)特定于應(yīng)用程序的資源和類(lèi),以及對(duì)應(yīng)用程序級(jí)操作的調(diào)用,比如啟動(dòng)活動(dòng),發(fā)送廣播和接收意圖等;
Activity, Service, Application 都是 Context 的子類(lèi)。Context 的具體實(shí)現(xiàn)類(lèi)是 ContextImpl, 還有一個(gè)包裝類(lèi)ContextWrapper, ContextWrapper 的子類(lèi)有 Service,
Application,ContextThemeWrapper, Activity 又是ContextThemeWrapper 的子類(lèi),
ContextThemeWrapper 也可以叫 UI Context,跟UI 操作相關(guān)的最好使用此類(lèi) Context。
ContextWrapper 中有個(gè) mBase,這個(gè) mBase 其實(shí)是ContextImpl,它是在Activity, Service, Application 創(chuàng)建時(shí)通過(guò) attachBaseContext() 方法將各自對(duì)對(duì)應(yīng)ContextImpl 賦值的。對(duì) context 的操作,最終實(shí)現(xiàn)都是在 ContextImpl。
對(duì)于 startActivity操作
- 當(dāng)為Activity Context則可直接使用
- 當(dāng)為其他Context, 則必須帶上
FLAG_ACTIVITY_NEW_TASK flags才能使用,因?yàn)榉?Activity context 啟動(dòng) Activity 沒(méi)有 Activity 棧,則無(wú)法啟動(dòng),因此需要加開(kāi)啟新的棧; - 另外UI相關(guān)要Activity中使用
getApplication()和getApplicationContext() 區(qū)別?
- 對(duì)于Activity/Service來(lái)說(shuō), getApplication()和getApplicationContext()的返回值完全相同; 除非廠商修改過(guò)接口;
- BroadcastReceiver在onReceive的過(guò)程, 能使用getBaseContext().getApplicationContext獲取所在Application, 而無(wú)法使用getApplication;
- ContentProvider能使用
getContext().getApplicationContext()獲取所在Application. 絕大多數(shù)情況下沒(méi)有問(wèn)題, 但是有可能會(huì)出現(xiàn)空指針的問(wèn)題, 情況如下:
當(dāng)同一個(gè)進(jìn)程有多個(gè)apk的情況下, 對(duì)于第二個(gè)apk是由provider方式拉起的, 前面介紹過(guò)provider創(chuàng)建過(guò)程并不會(huì)初始化所在application, 此時(shí)執(zhí)行g(shù)etContext().getApplicationContext()返回的結(jié)果便是NULL. 所以對(duì)于這種情況要做好判空.
1.5 IntentFilter是什么?有哪些使用場(chǎng)景?
IntentService是什么
IntentService是Service的子類(lèi),繼承與Service類(lèi),用于處理需要異步請(qǐng)求。用戶(hù)通過(guò)調(diào)用Context.StartService(Intent)發(fā)送請(qǐng)求,服務(wù)根據(jù)需要啟動(dòng),使用工作線程依次處理每個(gè)Intent,并在處理完所有工作后自身停止服務(wù)。
使用時(shí),擴(kuò)展IntentService并實(shí)現(xiàn)onHandleIntent(android.content.Intent)。IntentService接收Intent,啟動(dòng)工作線程,并在適當(dāng)時(shí)機(jī)停止服務(wù)。
所有的請(qǐng)求都在同一個(gè)工作線程上處理,一次處理一個(gè)請(qǐng)求,所以處理完所以的請(qǐng)求可能會(huì)花費(fèi)很長(zhǎng)的時(shí)間,但由于IntentService是另外了線程來(lái)工作,所以保證不會(huì)阻止App的主線程。
IntentService與Service的區(qū)別
從何時(shí)使用,觸發(fā)方法,運(yùn)行環(huán)境,何時(shí)停止四個(gè)方面分析。
何時(shí)使用
Service用于沒(méi)有UI工作的任務(wù),但不能執(zhí)行長(zhǎng)任務(wù)(長(zhǎng)時(shí)間的任務(wù)),如果需要Service來(lái)執(zhí)行長(zhǎng)時(shí)間的任務(wù),則必須手動(dòng)開(kāi)店一個(gè)線程來(lái)執(zhí)行該Service。
IntentService可用于執(zhí)行不與主線程溝通的長(zhǎng)任務(wù)。
觸發(fā)方法
Service通過(guò)調(diào)用 startService() 方法來(lái)觸發(fā)。而IntentService通過(guò)Intent來(lái)觸發(fā),開(kāi)啟一個(gè)新的工作線程,并在線程上調(diào)用 onHandleIntent() 方法。
運(yùn)行環(huán)境
Service 在App主線程上運(yùn)行,沒(méi)有與用戶(hù)交互,即在后臺(tái)運(yùn)行,如果執(zhí)行長(zhǎng)時(shí)間的請(qǐng)求任務(wù)會(huì)阻止主線程工作。
IntentService在自己?jiǎn)为?dú)開(kāi)啟的工作線程上運(yùn)行,即使執(zhí)行長(zhǎng)時(shí)間的請(qǐng)求任務(wù)也不會(huì)阻止主線程工作。
何時(shí)停止
如果執(zhí)行了Service,我們是有責(zé)任在其請(qǐng)求任務(wù)完成后關(guān)閉服務(wù),通過(guò)調(diào)用 stopSelf() 或 stopService()來(lái)結(jié)束服務(wù)。
IntentService會(huì)在執(zhí)行完所有的請(qǐng)求任務(wù)后自行關(guān)閉服務(wù),所以我們不必額外調(diào)用 stopSelf() 去關(guān)閉它。
1.6 談一談startService和bindService的區(qū)別,生命周期以及使用場(chǎng)景?
1、生命周期上的區(qū)別
執(zhí)行startService時(shí),Service會(huì)經(jīng)歷onCreate->onStartCommand。當(dāng)執(zhí)行stopService時(shí),直接調(diào)用onDestroy方法。調(diào)用者如果沒(méi)有stopService,Service
會(huì)一直在后臺(tái)運(yùn)行,下次調(diào)用者再起來(lái)仍然可以stopService。
執(zhí)行bindService時(shí),Service會(huì)經(jīng)歷onCreate->onBind。這個(gè)時(shí)候調(diào)用者和Service綁定在一起。調(diào)用者調(diào)用unbindService方法或者調(diào)用者Context不存在了(如Activity被finish了),Service就會(huì)調(diào)用onUnbind->onDestroy。這里所謂的綁定在一起就是說(shuō)兩者共存亡了。
多次調(diào)用startService,該Service只能被創(chuàng)建一次,即該Service的onCreate方法只會(huì)被調(diào)用一次。但是每次調(diào)用startService,onStartCommand方法都會(huì)被調(diào)用。Service的onStart方法在API 5時(shí)被廢棄,替代它的是onStartCommand方法。
第一次執(zhí)行bindService時(shí),onCreate和onBind方法會(huì)被調(diào)用,但是多次執(zhí)行bindService時(shí),onCreate和onBind方法并不會(huì)被多次調(diào)用,即并不會(huì)多次創(chuàng)建服務(wù)和綁定服務(wù)。
2、調(diào)用者如何獲取綁定后的Service的方法
onBind回調(diào)方法將返回給客戶(hù)端一個(gè)IBinder接口實(shí)例,IBinder允許客戶(hù)端回調(diào)服務(wù)的方法,比如得到Service運(yùn)行的狀態(tài)或其他操作。我們需要IBinder對(duì)象返回具體的Service對(duì)象才能操作,所以說(shuō)具體的Service對(duì)象必須首先實(shí)現(xiàn)Binder對(duì)象。
3、既使用startService又使用bindService的情況
如果一個(gè)Service又被啟動(dòng)又被綁定,則該Service會(huì)一直在后臺(tái)運(yùn)行。首先不管如何調(diào)用,onCreate始終只會(huì)調(diào)用一次。對(duì)應(yīng)startService調(diào)用多少次,Service的onStart
方法便會(huì)調(diào)用多少次。Service的終止,需要unbindService和stopService同時(shí)調(diào)用才行。不管startService與bindService的調(diào)用順序,如果先調(diào)用unbindService,此時(shí)服務(wù)不會(huì)自動(dòng)終止,再調(diào)用stopService之后,服務(wù)才會(huì)終止;如果先調(diào)用stopService,此時(shí)服務(wù)也不會(huì)終止,而再調(diào)用unbindService或者之前調(diào)用bindService的Context不存在了(如Activity被finish的時(shí)候)之后,服務(wù)才會(huì)自動(dòng)停止。
那么,什么情況下既使用startService,又使用bindService呢?
如果你只是想要啟動(dòng)一個(gè)后臺(tái)服務(wù)長(zhǎng)期進(jìn)行某項(xiàng)任務(wù),那么使用startService便可以了。如果你還想要與正在運(yùn)行的Service取得聯(lián)系,那么有兩種方法:一種是使用broadcast,另一種是使用bindService。前者的缺點(diǎn)是如果交流較為頻繁,容易造成性能上的問(wèn)題,而后者則沒(méi)有這些問(wèn)題。因此,這種情況就需要startService和bindService一起使用了。
另外,如果你的服務(wù)只是公開(kāi)一個(gè)遠(yuǎn)程接口,供連接上的客戶(hù)端(Android的Service是C/S架構(gòu))遠(yuǎn)程調(diào)用執(zhí)行方法,這個(gè)時(shí)候你可以不讓服務(wù)一開(kāi)始就運(yùn)行,而只是bindService,這樣在第一次bindService的時(shí)候才會(huì)創(chuàng)建服務(wù)的實(shí)例運(yùn)行它,這會(huì)節(jié)約很多系統(tǒng)資源,特別是如果你的服務(wù)是遠(yuǎn)程服務(wù),那么效果會(huì)越明顯(當(dāng)然Servcie創(chuàng)建是會(huì)花去一定時(shí)間,這點(diǎn)需要注意)。
4、本地服務(wù)與遠(yuǎn)程服務(wù)
本地服務(wù)依附在主進(jìn)程上,在一定程度上節(jié)約了資源。本地服務(wù)因?yàn)槭窃谕贿M(jìn)程,因此不需要IPC,也不需要AIDL。相應(yīng)bindService會(huì)方便很多。缺點(diǎn)是主進(jìn)程被kill后,服務(wù)變會(huì)終止。
遠(yuǎn)程服務(wù)是獨(dú)立的進(jìn)程,對(duì)應(yīng)進(jìn)程名格式為所在包名加上你指定的android:process字符串。由于是獨(dú)立的進(jìn)程,因此在Activity所在進(jìn)程被kill的是偶,該服務(wù)依然在運(yùn)行。缺點(diǎn)是該服務(wù)是獨(dú)立的進(jìn)程,會(huì)占用一定資源,并且使用AIDL進(jìn)行IPC稍微麻煩一點(diǎn)。
對(duì)于startService來(lái)說(shuō),不管是本地服務(wù)還是遠(yuǎn)程服務(wù),我們需要做的工作都一樣簡(jiǎn)單。
1.7 Service如何進(jìn)行?;睿?/h1>
- 利用系統(tǒng)廣播拉活
- 利用系統(tǒng)service拉活
- 利用Native進(jìn)程拉活<Android5.0以后失效> fork進(jìn)行監(jiān)控
- 主進(jìn)程,利用native拉活
- 利用JobScheduler機(jī)制拉活<Android5.0以后>
- 利用賬號(hào)同步機(jī)制拉活
1.8 簡(jiǎn)單介紹下ContentProvider是如何實(shí)現(xiàn)數(shù)據(jù)共享的?
ContentProvider(內(nèi)容提供者):對(duì)外提供了統(tǒng)一的訪問(wèn)數(shù)據(jù)的接口。
ContentResolver(內(nèi)容解析者):通過(guò)URI的不同來(lái)操作不同的ContentProvider中的數(shù)據(jù)。
ContentObserver(內(nèi)容觀察者):觀察特定URI引起的數(shù)據(jù)庫(kù)的變化。通過(guò)ContentResolver進(jìn)行注冊(cè),觀察數(shù)據(jù)是否發(fā)生變化及時(shí)通知刷新頁(yè)面(通過(guò)Handler通知主線程更新UI)。
1.9 說(shuō)下切換橫豎屏?xí)rActivity的生命周期?
1.AndroidManifest沒(méi)有設(shè)置configChanges屬性豎屏啟動(dòng):
onCreate -->onStart-->onResume
切換橫屏:
onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate-->onStart -->onRestoreInstanceState-->onResume -->onPause -->onStop -->onDestroy
(Android 6.0 Android 7.0 Android 8.0)
橫屏啟動(dòng):
onCreate -->onStart-->onResume
切換豎屏:
onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate-->onStart -->onRestoreInstanceState-->onResume -->onPause -->onStop -->onDestroy
(Android 6.0 Android 7.0 Android 8.0)
總結(jié):沒(méi)有設(shè)置configChanges屬性Android 6.0 7.0 8.0系統(tǒng)手機(jī) 表現(xiàn)都是一樣的,當(dāng)前的界面調(diào)用onSaveInstanceState走一遍流程,然后重啟調(diào)用onRestoreInstanceState再走一遍完整流程,最終destory。
2.AndroidManifest設(shè)置了android:configChanges="orientation"
豎屏啟動(dòng):
onCreate -->onStart-->onResume
切換橫屏:
onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate-->onStart -->onRestoreInstanceState-->onResume -->onPause -->onStop -->onDestroy
(Android 6.0)
onConfigurationChanged-->onPause -->onSaveInstanceState -->onStop ->onDestroy -->onCreate-->onStart -->onRestoreInstanceState-->onResume -->onPause -->onStop -->onDestroy
(Android 7.0)
onConfigurationChanged
(Android 8.0)
橫屏啟動(dòng):
onCreate -->onStart-->onResume
切換豎屏:
onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate-->onStart -->onRestoreInstanceState--> onResume -->onPause -->onStop -->onDestroy
(Android 6.0 )
onConfigurationChanged-->onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate-->onStart -->onRestoreInstanceState-->onResume -->onPause -->onStop -->onDestroy
(Android 7.0)
onConfigurationChanged
(Android 8.0)
總結(jié):設(shè)置了configChanges屬性為orientation之后,Android6.0 同沒(méi)有設(shè)置configChanges情況相同,完整的走完了兩個(gè)生命周期,調(diào)用了onSaveInstanceState和onRestoreInstanceState方法;Android 7.0則會(huì)先回調(diào)onConfigurationChanged方法,剩下的流程跟Android6.0 保持一致;Android 8.0 系統(tǒng)更是簡(jiǎn)單,只是回調(diào)了onConfigurationChanged方法,并沒(méi)有走Activity的生命周期方法。
3.AndroidManifest設(shè)置了android:configChanges="orientation|keyboardHidden|screenSize"
豎(橫)屏啟動(dòng):onCreate -->onStart-->onResume
切換橫(豎)屏:onConfigurationChanged (Android 6.0
Android 7.0 Android 8.0)
總結(jié):設(shè)置android:configChanges="orientation|keyboardHidden|screenSize" 則都不會(huì)調(diào)用Activity的其他生命周期方法,只會(huì)調(diào)用onConfigurationChanged方法。
4.AndroidManifest設(shè)置了android:configChanges="orientation|screenSize"
豎(橫)屏啟動(dòng):onCreate -->onStart-->onResume
切換橫(豎)屏:onConfigurationChanged (Android 6.0Android 7.0 Android 8.0)
總結(jié):沒(méi)有了keyboardHidden跟3是相同的,orientation
代表橫豎屏切換 screenSize代表屏幕大小發(fā)生了改變,設(shè)置了這兩項(xiàng)就不會(huì)回調(diào)Activity的生命周期的方法,只會(huì)回調(diào)onConfigurationChanged 。
5.AndroidManifest設(shè)置了android:configChanges="orientation|keyboardHidden"
總結(jié):跟只設(shè)置了orientation屬性相同,Android6.0Android7.0會(huì)回調(diào)生命周期的方法,Android8.0則只回調(diào)onConfigurationChanged。說(shuō)明如果設(shè)置了orientation
和 screenSize 都不會(huì)走生命周期的方法,keyboardHidden不影響。
- 不設(shè)置configChanges屬性不會(huì)回調(diào)onConfigurationChanged,且切屏的時(shí)候會(huì)回調(diào)生命周期方法。
- 只有設(shè)置了orientation 和 screenSize 才會(huì)保證都不會(huì)走生命周期,且切屏只回調(diào)onConfigurationChanged。
- 設(shè)置orientation,沒(méi)有設(shè)置screenSize,切屏?xí)卣{(diào)onConfigurationChanged,但是還會(huì)走生命周期方法。
注:這里只選擇了Android部分系統(tǒng)的手機(jī)做測(cè)試,由于不同系統(tǒng)的手機(jī)品牌也不相同,可能略微會(huì)有區(qū)別。
另:代碼動(dòng)態(tài)設(shè)置橫豎屏狀態(tài)(onConfigurationChanged當(dāng)屏幕發(fā)生變化的時(shí)候回調(diào))
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
獲取屏幕狀態(tài)(int ORIENTATION_PORTRAIT = 1; 豎屏 int ORIENTATION_LANDSCAPE = 2; 橫屏)
int screenNum = getResources().getConfiguration().orientation;
configChanges屬性
- orientation 屏幕在縱向和橫向間旋轉(zhuǎn)
- keyboardHidden 鍵盤(pán)顯示或隱藏
- screenSize 屏幕大小改變了
- fontScale 用戶(hù)變更了首選的字體大小
- locale 用戶(hù)選擇了不同的語(yǔ)言設(shè)定
- keyboard 鍵盤(pán)類(lèi)型變更,例如手機(jī)從12鍵盤(pán)切換到全鍵盤(pán)
- touchscreen或navigation 鍵盤(pán)或?qū)Ш椒绞阶兓?,一般不?huì)發(fā)生這樣的事件
常用的包括:orientation keyboardHidden screenSize,設(shè)置這三項(xiàng)界面不會(huì)走Activity的生命周期,只會(huì)回調(diào)onConfigurationChanged方法。
screenOrientation屬性
- unspecified 默認(rèn)值,由系統(tǒng)判斷狀態(tài)自動(dòng)切換
- landscape 橫屏
- portrait 豎屏
- user 用戶(hù)當(dāng)前設(shè)置的orientation值
- behind 下一個(gè)要顯示的Activity的orientation值
- sensor 使用傳感器 傳感器的方向
- nosensor 不使用傳感器 基本等同于unspecified僅landscape和portrait常用,代表界面默認(rèn)是橫屏或者豎屏,還可以再代碼中更改。
1.10 Activity中onNewIntent方法的調(diào)用時(shí)機(jī)和使用場(chǎng)景?
Activity 的 onNewIntent方法的調(diào)用可總結(jié)如下:
在該Activity的實(shí)例已經(jīng)存在于Task和Back stack中(或者通俗的說(shuō)可以通過(guò)按返回鍵返回到該Activity )時(shí),當(dāng)使用intent來(lái)再次啟動(dòng)該Activity的時(shí)候,如果此次啟動(dòng)不創(chuàng)建該Activity的新實(shí)例,則系統(tǒng)會(huì)調(diào)用原有實(shí)例的onNewIntent()方法來(lái)處理此intent.
且在下面情況下系統(tǒng)不會(huì)創(chuàng)建該Activity的新實(shí)例:
1,如果該Activity在Manifest中的android:launchMode定義為singleTask或者singleInstance.
2,如果該Activity在Manifest中的android:launchMode定義為singleTop且該實(shí)例位于Backstack的棧頂.
3,如果該Activity在Manifest中的android:launchMode定義為singleTop,且上述intent包含Intent.FLAG_ACTIVITY_CLEAR_TOP標(biāo)志.
4,如果上述intent中包含Intent.FLAG_ACTIVITY_CLEAR_TOP 標(biāo)志和且包含Intent.FLAG_ACTIVITY_SINGLE_TOP 標(biāo)志.
5,如果上述intent中包含Intent.FLAG_ACTIVITY_SINGLE_TOP 標(biāo)志且該實(shí)例位于Back stack的棧頂.
上述情況滿(mǎn)足其一,則系統(tǒng)將不會(huì)創(chuàng)建該Activity的新實(shí)例.
根據(jù)現(xiàn)有實(shí)例所處的狀態(tài)不同onNewIntent()方法的調(diào)用時(shí)機(jī)也不同,總的說(shuō)如果系統(tǒng)調(diào)用onNewIntent()方法則系統(tǒng)會(huì)在onResume()方法執(zhí)行之前調(diào)用它.這也是官方API為什么只說(shuō)"you can count on onResume() being called after this method",而不具體說(shuō)明調(diào)用時(shí)機(jī)的原因.
1.11 Intent傳輸數(shù)據(jù)的大小有限制嗎?如何解決?
Intent 中的 Bundle 是使用 Binder 機(jī)制進(jìn)行數(shù)據(jù)傳送的,數(shù)據(jù)會(huì)寫(xiě)到內(nèi)核空間, Binder 緩沖區(qū)域;
Binder 的緩沖區(qū)是有大小限制的, 有些 ROM 是 1M, 有些ROM 是 2M;
這個(gè)限制定義在frameworks/native/libs/binder/processState.cpp 類(lèi)中,如果超過(guò)這個(gè)限制, 系統(tǒng)就會(huì)報(bào)錯(cuò);
#define BINDER_VM_SIZE ((1*1024*1024) - (4096*2)) ;
因?yàn)?Binder 本身就是為了進(jìn)程間頻繁-靈活的通信所設(shè)計(jì)的, 并不是為了拷貝大量數(shù)據(jù);
如果非 ipc 就很簡(jiǎn)單了, static 變量, eventBus 之類(lèi)的都可以;
如果是 ipc, 一定要一次性傳大文件, 可以用 file 或者 socket;
1.12 說(shuō)說(shuō)ContentProvider、ContentResolver、ContentObserver 之間的關(guān)系?
ContentProvider
內(nèi)容提供者, 用于對(duì)外提供數(shù)據(jù),比如聯(lián)系人應(yīng)用中就是用了ContentProvider,
一個(gè)應(yīng)用可以實(shí)現(xiàn)ContentProvider來(lái)提供給別的應(yīng)用操作,通過(guò)ContentResolver來(lái)操作別的應(yīng)用數(shù)據(jù)
ContentResolver
內(nèi)容解析者, 用于獲取內(nèi)容提供者提供的數(shù)據(jù)
ContentResolver.notifyChange(uri)發(fā)出消息ContentObserver
內(nèi)容監(jiān)聽(tīng)者,可以監(jiān)聽(tīng)數(shù)據(jù)的改變狀態(tài)
觀察(捕捉)特定的Uri引起的數(shù)據(jù)庫(kù)的變化
ContentResolver.registerContentObserver()監(jiān)聽(tīng)消息
概括:
使用ContentResolver來(lái)獲取ContentProvider提供的數(shù)據(jù),同時(shí)注冊(cè)ContentObserver監(jiān)聽(tīng)數(shù)據(jù)的變化
1.13說(shuō)說(shuō)Activity加載的流程?
App 啟動(dòng)流程(基于Android8.0)
- 點(diǎn)擊桌面 App 圖標(biāo),Launcher 進(jìn)程采用 Binder IPC(具體為ActivityManager.getService 獲取 AMS 實(shí)例)向 system_server 的 AMS 發(fā)起startActivity 請(qǐng)求
- system_server 進(jìn)程收到請(qǐng)求后,向 Zygote 進(jìn)程發(fā)送創(chuàng)建進(jìn)程的請(qǐng)求;
- Zygote 進(jìn)程 fork 出新的子進(jìn)程,即 App 進(jìn)程
- App 進(jìn)程創(chuàng)建即初始化 ActivityThread,然后通過(guò)Binder IPC 向 system_server 進(jìn)程的 AMS 發(fā)起 attachApplication 請(qǐng)求
- system_server 進(jìn)程的 AMS 在收到 attachApplication請(qǐng)求后,做一系列操作后,通知 ApplicationThread bindApplication,然后發(fā)送 H.BIND_APPLICATION 消
息 - 主線程收到 H.BIND_APPLICATION 消息,調(diào)用handleBindApplication 處理后做一系列的初始化操作,初始化 Application 等
- system_server 進(jìn)程的 AMS 在 bindApplication 后,會(huì)調(diào)用ActivityStackSupervisor.attachApplicationLocked,之后經(jīng)過(guò)一系列操作,在 realStartActivityLocked 方法通過(guò) Binder IPC 向 App 進(jìn)程發(fā)送 scheduleLaunchActivity 請(qǐng)求;
- App進(jìn)程的 binder 線程(ApplicationThread)在收到請(qǐng)求后,通過(guò) handler 向主線程發(fā)送 LAUNCH_ACTIVITY 消息;
- 主線程收到 message 后經(jīng)過(guò) handleLaunchActivity,performLaunchActivity 方法,然后通過(guò)反射機(jī)制創(chuàng)建目標(biāo) Activity;
- 通過(guò) Activity attach 方法創(chuàng)建 window 并且和 Activity關(guān)聯(lián),然后設(shè)置 WindowManager 用來(lái)管理 window,然后通知 Activity 已創(chuàng)建,即調(diào)用 onCreate 然后調(diào)用 handleResumeActivity,Activity 可見(jiàn)
補(bǔ)充: - ActivityManagerService 是一個(gè)注冊(cè)到 SystemServer 進(jìn)程并實(shí)現(xiàn)了 IActivityManager 的 Binder,可以通過(guò) ActivityManager 的 getService 方法獲取 AMS 的代理對(duì)象,進(jìn)而調(diào)用 AMS 方法
- ApplicationThread 是 ActivityThread 的內(nèi)部類(lèi),是一個(gè)實(shí)現(xiàn)了 IApplicationThread 的 Binder。AMS通過(guò)Binder IPC 經(jīng) ApplicationThread 對(duì)應(yīng)用進(jìn)行控制
- 普通的 Activity 啟動(dòng)和本流程差不多,至少不需要再創(chuàng)建 App 進(jìn)程了
- Activity A 啟動(dòng) Activity B,A 先 pause 然后 B 才能resume,因此在 onPause 中不能做耗時(shí)操作,不然會(huì)影響下一個(gè) Activity 的啟動(dòng)