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)應(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), 它允許訪(fǎng)問(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狮崩,它是在A(yíng)ctivity, 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ì)于A(yíng)ctivity/Service來(lái)說(shuō), getApplication()和getApplicationContext()的返回值完全相同; 除非廠(chǎng)商修改過(guò)接口;
- BroadcastReceiver在onReceive的過(guò)程, 能使用getBaseContext().getApplicationContext獲取所在A(yíng)pplication, 而無(wú)法使用getApplication;
- ContentProvider能使用
getContext().getApplicationContext()獲取所在A(yíng)pplication. 絕大多數(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)尖奔,使用工作線(xiàn)程依次處理每個(gè)Intent,并在處理完所有工作后自身停止服務(wù)穷当。
使用時(shí)提茁,擴(kuò)展IntentService并實(shí)現(xiàn)onHandleIntent(android.content.Intent)。IntentService接收Intent馁菜,啟動(dòng)工作線(xiàn)程茴扁,并在適當(dāng)時(shí)機(jī)停止服務(wù)。
所有的請(qǐng)求都在同一個(gè)工作線(xiàn)程上處理汪疮,一次處理一個(gè)請(qǐng)求峭火,所以處理完所以的請(qǐng)求可能會(huì)花費(fèi)很長(zhǎng)的時(shí)間毁习,但由于IntentService是另外了線(xiàn)程來(lái)工作,所以保證不會(huì)阻止App的主線(xiàn)程卖丸。
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è)線(xiàn)程來(lái)執(zhí)行該Service。
IntentService可用于執(zhí)行不與主線(xiàn)程溝通的長(zhǎng)任務(wù)为鳄。
觸發(fā)方法
Service通過(guò)調(diào)用 startService() 方法來(lái)觸發(fā)裳仆。而IntentService通過(guò)Intent來(lái)觸發(fā),開(kāi)啟一個(gè)新的工作線(xiàn)程孤钦,并在線(xiàn)程上調(diào)用 onHandleIntent() 方法歧斟。
運(yùn)行環(huán)境
Service 在A(yíng)pp主線(xiàn)程上運(yùn)行,沒(méi)有與用戶(hù)交互偏形,即在后臺(tái)運(yùn)行静袖,如果執(zhí)行長(zhǎng)時(shí)間的請(qǐng)求任務(wù)會(huì)阻止主線(xiàn)程工作。
IntentService在自己?jiǎn)为?dú)開(kāi)啟的工作線(xiàn)程上運(yùn)行俊扭,即使執(zhí)行長(zhǎng)時(shí)間的請(qǐng)求任務(wù)也不會(huì)阻止主線(xiàn)程工作队橙。
何時(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方法在A(yíng)PI 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)程,因此在A(yíng)ctivity所在進(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)行钡对啵活?
- 利用系統(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)一的訪(fǎng)問(wèn)數(shù)據(jù)的接口。
ContentResolver(內(nèi)容解析者):通過(guò)URI的不同來(lái)操作不同的ContentProvider中的數(shù)據(jù)轮傍。
ContentObserver(內(nèi)容觀(guān)察者):觀(guān)察特定URI引起的數(shù)據(jù)庫(kù)的變化暂雹。通過(guò)ContentResolver進(jìn)行注冊(cè),觀(guān)察數(shù)據(jù)是否發(fā)生變化及時(shí)通知刷新頁(yè)面(通過(guò)Handler通知主線(xiàn)程更新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)
觀(guān)察(捕捉)特定的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)流程(基于A(yíng)ndroid8.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 消
息 - 主線(xiàn)程收到 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 線(xiàn)程(ApplicationThread)在收到請(qǐng)求后,通過(guò) handler 向主線(xiàn)程發(fā)送 LAUNCH_ACTIVITY 消息夜涕;
- 主線(xiàn)程收到 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)