面試專題我放在git上了间景,地址Github 歡迎fork然后一起更新
Activity的面試基礎(chǔ)詳解
1团秽,activity的四種狀態(tài)
running、paused拘哨、stopped、killed
2信峻,Android的進(jìn)程優(yōu)先級(jí)
前臺(tái) / 可見 / 服務(wù) / 后臺(tái) / 空
3倦青,Android的任務(wù)棧,啟動(dòng)模式
棧:先進(jìn)后出
standard (sidadende) 默認(rèn)模式盹舞,每次啟動(dòng)會(huì)創(chuàng)建新實(shí)例
singleTop 棧頂復(fù)用模式 姨夹,新activity在棧頂,就復(fù)用矾策,并回調(diào)onNewIntent方法磷账;如果存在且不再棧頂,那么Activity會(huì)被重新創(chuàng)建贾虽;
使用場景:瀏覽器的書簽逃糟,通訊消息聊天界面
singleTask 棧內(nèi)復(fù)用模式,檢查整個(gè)棧內(nèi)如果有那就復(fù)用蓬豁,并回調(diào)onNewIntent方法绰咽;此模式啟動(dòng) Activity A,系統(tǒng)首先會(huì)尋找是否存在 A 想要的任務(wù)棧地粪,如果不存在取募,就會(huì)重新創(chuàng)建一個(gè)任務(wù)棧,然后把創(chuàng)建好 A 的實(shí)例放到棧中蟆技;
使用場景:某個(gè)Activity當(dāng)做主界面的時(shí)候
singleInstance 單實(shí)例模式玩敏,加強(qiáng)版singleTask斗忌,該Activity只能單獨(dú)位于一個(gè)任務(wù)棧且該棧只有它一個(gè)
使用場景:比如瀏覽器BrowserActivity很耗內(nèi)存,很多app都會(huì)要調(diào)用它旺聚,這樣就可以把該Activity設(shè)置成單例模式织阳。比如:鬧鐘鬧鈴。
4砰粹,Scheme跳轉(zhuǎn)協(xié)議
通過自定義scheme協(xié)議唧躲,方便跳轉(zhuǎn)app中的各個(gè)頁面
通過scheme協(xié)議,服務(wù)器可以定制化告訴App跳轉(zhuǎn)到那個(gè)頁面
通過通知欄消息定制化跳轉(zhuǎn)頁面碱璃,通過H5頁面跳轉(zhuǎn)頁面等弄痹。
5,生命周期
啟動(dòng): onCreate (用戶不可見) -> onStart (用戶可見但不在前臺(tái)在后臺(tái)嵌器,無法與用戶交互) -> onResume (用戶可見界酒,在前臺(tái)并獲得焦點(diǎn))
點(diǎn)擊Home回主界面(Activity不可見) -> onPause -> onStop
再次回到原Activity -> onRestart -> onStart -> onResume
退出Activity -> onPause -> onStop -> onDestory
- onCreate:創(chuàng)建,常用來初始化工作嘴秸,比如調(diào)用 setContentView 加載界面布局資源,初始化 Activity 所需數(shù)據(jù)等庇谆;
- onDestroy:表即將被銷毀岳掐,這是 Activity 生命周期中的最后一個(gè)回調(diào),常做回收工作饭耳、資源釋放串述;
- onStart:啟動(dòng),此時(shí) Activity 可見但不在前臺(tái)寞肖,還處于后臺(tái)纲酗,無法與用戶交互;
- onStop:即將停止新蟆,可以做一些稍微重量級(jí)的回收工作觅赊,比如注銷廣播接收器、關(guān)閉網(wǎng)絡(luò)連接等琼稻,同樣不能太耗時(shí)吮螺;
- onResume:獲得焦點(diǎn),此時(shí) Activity 可見且在前臺(tái)并開始活動(dòng)帕翻,這是與 onStart 的區(qū)別所在鸠补;
- onPause:正在停止,可做存儲(chǔ)數(shù)據(jù)嘀掸、停止動(dòng)畫等工作紫岩,但是不能太耗時(shí),因?yàn)闀?huì)影響到新 Activity的顯示睬塌,onPause 必須先執(zhí)行完泉蝌,新 Activity 的 onResume 才會(huì)執(zhí)行歇万;
- onRestart: 重新啟動(dòng),一般情況下梨与,當(dāng)前Acitivty 從不可見重新變?yōu)榭梢姇r(shí)堕花,OnRestart 就會(huì)被調(diào)用;
6粥鞋,Activity A 啟動(dòng)另一個(gè) Activity B 會(huì)調(diào)用哪些方法缘挽?如果 B 是透明主題的又或則是個(gè) DialogActivity 呢 ?
Activity A 啟動(dòng)另一個(gè) Activity B呻粹,回調(diào)如下
Activity A 的 onPause() → Activity B 的 onCreate() →onStart() → onResume() → Activity A 的 onStop()壕曼;
如果 B 是透明主題又或則是個(gè) DialogActivity,則不會(huì)回調(diào) A 的onStop等浊;
7腮郊,說下 onSaveInstanceState()方法的作用 ? 何時(shí)會(huì)被調(diào)用?
異常情況下(系統(tǒng)配置發(fā)生改變時(shí)導(dǎo)致 Activity被殺死并重新創(chuàng)建筹燕、資源內(nèi)存不足導(dǎo)致低優(yōu)先級(jí)的 Activity 被殺死)
- 系統(tǒng)會(huì)調(diào)用 onSaveInstanceState 來保存當(dāng)前 Activity 的狀態(tài)轧飞,此方法調(diào)用在 onStop 之前,與 onPause 沒有既定的時(shí)序關(guān)系撒踪;
-
當(dāng) Activity 被重建后过咬,系統(tǒng)會(huì)調(diào)用 onRestoreInstanceState,并且把 onSaveInstanceState方法所保存的 Bundle 對(duì)象同時(shí)傳參給onRestoreInstanceState和 onCreate()制妄,因此可以通過這兩個(gè)方法判斷Activity 是否被重建掸绞,調(diào)用在 onStart 之后;
image.png
8耕捞,了解哪些 Activity 常用的標(biāo)記位 Flags衔掸?
FLAG_ACTIVITY_NEW_TASK : 對(duì)應(yīng) singleTask 啟動(dòng)模式,其效果和在 XML 中指定該啟動(dòng)模式相同俺抽;
FLAG_ACTIVITY_SINGLE_TOP : 對(duì)應(yīng) singleTop 啟動(dòng)模式敞映,其效果和在 XML 中指定該啟動(dòng)模式相同;
FLAG_ACTIVITY_CLEAR_TOP : 具有此標(biāo)記位的 Activity磷斧,當(dāng)它啟動(dòng)時(shí)驱显,在同一個(gè)任務(wù)棧中所有位于它上面的 Activity 都要出棧。
這個(gè)標(biāo)記位一般會(huì)和 singleTask 模式一起出現(xiàn)瞳抓,在這種情況下埃疫,被啟動(dòng) Activity 的實(shí)例如果已經(jīng)存在,那么系統(tǒng)就會(huì)回調(diào)onNewIntent孩哑。如果被啟動(dòng)的 Activity 采用 standard 模式啟動(dòng)栓霜,那么它以及連同它之上的 Activity 都要出棧,系統(tǒng)會(huì)創(chuàng)建新的Activity 實(shí)例并放入棧中横蜒;
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS : 具有這個(gè)標(biāo)記的Activity 不會(huì)出現(xiàn)在歷史 Activity 列表中胳蛮;
9销凑,說下 Activity 跟 window,view 之間的關(guān)系仅炊?
Activity 創(chuàng)建時(shí)通過 attach()初始化了一個(gè) Window 也就是PhoneWindow斗幼,一個(gè) PhoneWindow 持有一個(gè) DecorView 的實(shí)例,
DecorView 本身是一個(gè) FrameLayout抚垄,繼承于 View蜕窿,Activty 通過setContentView 將 xml 布局控件不斷 addView()添加到 View 中,
最終顯示到 Window 于我們交互呆馁;
Activity剪窗花的人(控制的)桐经;Window窗戶(承載的一個(gè)模型);View窗花(要顯示的視圖View)浙滤;LayoutInflater剪刀---將布局(圖紙)剪成窗花阴挣。
這個(gè)問題真的很不好回答。所以這里先來個(gè)算是比較恰當(dāng)?shù)谋扔鱽硇稳菹滤鼈兊年P(guān)系吧纺腊。Activity像一個(gè)工匠(控制單元)畔咧,Window像窗戶(承載模型),View像窗花(顯示視圖)LayoutInflater像剪刀揖膜,Xml配置像窗花圖紙誓沸。
1:Activity構(gòu)造的時(shí)候會(huì)初始化一個(gè)Window,準(zhǔn)確的說是PhoneWindow次氨。
2:這個(gè)PhoneWindow有一個(gè)“ViewRoot”,這個(gè)“ViewRoot”是一個(gè)View或者說ViewGroup摘投,是最初始的根視圖煮寡。
3:“ViewRoot”通過addView方法來一個(gè)個(gè)的添加View。比如TextView犀呼,Button等
4:這些View的事件監(jiān)聽幸撕,是由WindowManagerService來接受消息,并且回調(diào)Activity函數(shù)外臂。比如onClickListener坐儿,onKeyDown等。
10宋光,橫豎屏切換的 Activity 生命周期變化貌矿?
不設(shè)置 Activity 的 android:configChanges 時(shí),切屏?xí)N毀當(dāng)前Activity罪佳,然后重新加載調(diào)用各個(gè)生命周期逛漫,切橫屏?xí)r會(huì)執(zhí)行一次,切豎屏?xí)r會(huì)執(zhí)行兩次赘艳; onPause()→onStop()→onDestory()→onCreate()→onStart()→onResume()
-
設(shè)置 Activity 的 android:configChanges="orientation"酌毡,經(jīng)過機(jī)型測試
在 Android5.1 即 API 23 級(jí)別下克握,切屏還是會(huì)重新調(diào)用各個(gè)生命周期,切橫枷踏、豎屏?xí)r只會(huì)執(zhí)行一次 在 Android 9 即 API 28 級(jí)別下菩暗,切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行 onConfigurationChanged 方法
官方糾正后旭蠕,原話如下
如果您的應(yīng)用面向 Android 3.2 即 API 級(jí)別 13 或更高級(jí)別(按照 minSdkVersion 和 targetSdkVersion屬性所聲明的級(jí)別)停团,則還應(yīng)聲明 "screenSize" 配置,因?yàn)楫?dāng)設(shè)備在橫向與縱向之間切換時(shí)下梢,該配置也會(huì)發(fā)生變化客蹋。即便是在 Android 3.2 或更高版本的設(shè)備上運(yùn)行,此配置變更也不會(huì)重新啟動(dòng)Activity
- 設(shè)置 Activity 的android:configChanges="orientation|keyboardHidden|screenSize"時(shí)孽江,機(jī)型測試通過讶坯,切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行 onConfigurationChanged 方法岗屏;
11辆琅,如何啟動(dòng)其他應(yīng)用的 Activity?
在保證有權(quán)限訪問的情況下这刷,通過隱式 Intent 進(jìn)行目標(biāo)Activity 的 IntentFilter 匹配婉烟,原則是:
一個(gè) intent 只有同時(shí)匹配某個(gè) Activity 的 intentfilter 中的 action、category暇屋、data 才算完全匹配似袁,才能啟動(dòng)該 Activity琉预;
一個(gè) Activity 可以有多個(gè) intent-filter圈膏,一個(gè) intent只要成功匹配任意一組 intent-filter步藕,就可以啟動(dòng)該Activity曙强;
12诈嘿,Activity 的啟動(dòng)過程孽拷?
- 點(diǎn)擊 App 圖標(biāo)后通過 startActivity 遠(yuǎn)程調(diào)用到 AMS 中偎球,AMS 中將新啟動(dòng)的 activity 以 activityrecord 的結(jié)構(gòu)壓入 activity棧中瞳秽,并通過遠(yuǎn)程 binder 回調(diào)到原進(jìn)程联予,使得原進(jìn)程進(jìn)入 pause狀態(tài)啼县,原進(jìn)程 pause 后通知 AMS 我 pause 了
- 此時(shí) AMS 再根據(jù)棧中 Activity 的啟動(dòng) intent 中的 flag 是否含有 new_task 的標(biāo)簽判斷是否需要啟動(dòng)新進(jìn)程,啟動(dòng)新進(jìn)程通過startProcessXXX 的函數(shù)
-
啟動(dòng)新進(jìn)程后通過反射調(diào)用 ActivityThread 的 main 函數(shù)沸久,main函數(shù)中調(diào)用 looper.prepar 和 lopper.loop 啟動(dòng)消息隊(duì)列循環(huán)機(jī)制季眷。最后遠(yuǎn)程告知 AMS 我啟動(dòng)了。AMS 回調(diào)handleLauncherAcitivyt 加載 activity卷胯。在handlerLauncherActivity 中會(huì)通過反射調(diào)用 Application 的onCreate 和 activity 的 onCreate 以及通過handleResumeActivity 中反射調(diào)用 Activity 的 onResume
image.png
13瘟裸,Activity之間傳值有哪幾種方法?
1诵竭,通過Intent直接傳參數(shù)
2话告,通過Bundle封裝數(shù)據(jù)傳指
3兼搏,通過startActivityforResult回調(diào),接口回調(diào)
4沙郭,通過發(fā)送廣播的形式佛呻,數(shù)據(jù)需要序列化
5,通過存儲(chǔ)介質(zhì)病线,比如數(shù)據(jù)庫吓著,sharedpreference,文件等
6送挑,通過事件總線EventBus形式
14绑莺,設(shè)備橫豎屏切換的時(shí)候,接下來會(huì)發(fā)生什么惕耕?
1纺裁、不設(shè)置Activity的android:configChanges時(shí),切屏?xí)匦抡{(diào)用各個(gè)生命周期司澎,切橫屏?xí)r會(huì)執(zhí)行一次欺缘,切豎屏?xí)r會(huì)執(zhí)行兩次
2、設(shè)置Activity的android:configChanges=”orientation”時(shí)挤安,切屏還是會(huì)重新調(diào)用各個(gè)生命周期谚殊,切橫、豎屏?xí)r只會(huì)執(zhí)行一次
3蛤铜、設(shè)置Activity的android:configChanges=”orientation|keyboardHidden”時(shí)嫩絮,切屏不會(huì)重新調(diào)用各個(gè)生命周期,只會(huì)執(zhí)行onConfigurationChanged方法
Fragment的面試詳解
1围肥,F(xiàn)ragment為什么被稱為第五大組件
Fragment一開始是用于平板的擴(kuò)展頁面剿干,后面全部應(yīng)用于Activity內(nèi)部切換
Fragment有生命周期,切依附于Activity
2虐先,F(xiàn)ragment的加載到Activity的2種方式
- 添加Fragment到Activity的布局文件xml中
- 動(dòng)態(tài)在Activity中添加Fragment
3怨愤,F(xiàn)ragmentPagerAdapter與FragmentStatePagerAdapter的區(qū)別派敷?
二者都繼承 PagerAdapter
- 前者適用于頁面較少蛹批,數(shù)據(jù)相對(duì)靜態(tài)的頁面,F(xiàn)ragment數(shù)量較少的情況篮愉,其destroyItem方法里是detach腐芍,并不會(huì)回收內(nèi)存
- 后者適用于頁面較多,數(shù)據(jù)動(dòng)態(tài)性較大试躏,占用內(nèi)存較多猪勇,多Fragment的情況,其destoryItem里面是remove颠蕴,會(huì)釋放內(nèi)存泣刹;頁面不可見會(huì)移除Fragment釋放資源
viewpager中助析,fragment嵌套fragment的時(shí)候必須使用FragmentStatePageAdapter才起作用
4,F(xiàn)ragment的生命周期
Fragment生命周期比Activity多5個(gè)方法椅您,F(xiàn)ragment里沒有onRestart
onAttach外冀,onDetach,onCreateView掀泳,onDestoryView
onViewCreated和onActivityCreated
5雪隧,F(xiàn)ragment的通信
- 在frgment中調(diào)用Activity中的方法,getActivity
- 在Activity中調(diào)用Fragment中的方法员舵,接口回調(diào)
- 在Fragment中調(diào)用Fragment中的方法脑沿,findFragmentById
6,getFragmentManager马僻、getSupportFragmentManager 庄拇、getChildFragmentManager 之間的區(qū)別?
- getFragmentManager()所得到的是所在 fragment 的父容器的管理器巫玻, getChildFragmentManager()所得到的是在fragment 里面子容器的管理器丛忆, 如果是 fragment 嵌套fragment,那么就需要利用getChildFragmentManager()仍秤;
- 因?yàn)?Fragment 是 3.0 Android 系統(tǒng) API 版本才出現(xiàn)的組件熄诡,所以 3.0 以上系統(tǒng)可以直接調(diào)用getFragmentManager()來獲取 FragmentManager()對(duì)象,而 3.0 以下則需要調(diào)用 getSupportFragmentManager() 來間接獲仁Α凰浮;
7,F(xiàn)ragment中的add與replace的區(qū)別(Fragment重疊)
- add 不會(huì)重新初始化fragment苇本,replace每次都會(huì)袜茧。所以如果在fragment生命周期內(nèi)獲取數(shù)據(jù),使用replace會(huì)重復(fù)獲取瓣窄。
- 添加相同的 fragment 時(shí)笛厦,replace 不會(huì)有任何變化,add會(huì)報(bào) IllegalStateException 異常
- replace 先 remove 掉相同 id 的所有 fragment俺夕,然后在add 當(dāng)前的這個(gè) fragment裳凸,而 add 是覆蓋前一個(gè)fragment。所以如果使用 add 一般會(huì)伴隨 hide()和show()劝贸,避免布局重疊姨谷;
- 使用 add,如果應(yīng)用放在后臺(tái)映九,或以其他方式被系統(tǒng)銷毀梦湘,再打開時(shí),hide()中引用的 fragment 會(huì)銷毀,所以依然會(huì)出現(xiàn)布局重疊 bug捌议,可以使用 replace 或使用 add時(shí)哼拔,添加一個(gè) tag 參數(shù);
Service面試詳解
參考:https://blog.csdn.net/javazejian/article/details/52709857
1瓣颅,Service是什么管挟?
Service是一個(gè)一種可以在后臺(tái)執(zhí)行長時(shí)間運(yùn)行操作而沒有用戶界面的應(yīng)用組件,無法做耗時(shí)的操作
2弄捕,Service和Thread的區(qū)別
service運(yùn)行在主線程中僻孝,無法做耗時(shí)的操作
thread是線程的最小單元,一般指耗時(shí)線程
3守谓,Service啟動(dòng)方式
- startService
- 定義一個(gè)類繼承Service
- 在Manifest.xml文件中配置該service
- 使用context的startService方法啟動(dòng)
- 不再使用時(shí)穿铆,調(diào)用stopService方法停止該服務(wù)
- bindService
- 創(chuàng)建bindservice服務(wù)端,繼承自service并在類中斋荞,創(chuàng)建一個(gè)實(shí)現(xiàn)IBinder接口的實(shí)例對(duì)象并提供公共方法給客戶端調(diào)用
- 從onBind回調(diào)方法返回此Binder實(shí)例
- 在客戶端中荞雏,從onServiceConnected回調(diào)方法接受Binder,并私用提供的方法調(diào)用綁定服務(wù)平酿。
4凤优,IntentService面試詳解
如果有一個(gè)任務(wù),可以分成很多個(gè)子任務(wù)蜈彼,需要按照順序來完成筑辨,如果需要放到一個(gè)服務(wù)中完成,那么使用IntentService是最好的選擇幸逆。
Service是運(yùn)行在主線程當(dāng)中的棍辕,所以在service里面編寫耗時(shí)的操作代碼,則會(huì)卡主線程會(huì)ANR还绘。為了解決這樣的問題楚昭,谷歌引入了IntentService
- 一種特殊的service,繼承自service并且本身就是一個(gè)抽象類
- 內(nèi)部通過HandlerThread和Handler實(shí)現(xiàn)異步操作拍顷,所以它可以做耗時(shí)的操作抚太,內(nèi)部適中也是通過handler異步
- 本質(zhì)就是一個(gè)封裝了HandlerThred和handler的異步框架
- 它創(chuàng)建了一個(gè)獨(dú)立的工作線程來處理所有一個(gè)一個(gè)的intent,創(chuàng)建了一個(gè)工作隊(duì)列來逐個(gè)發(fā)送intent給onHandlerIntent()
- 不需要主動(dòng)調(diào)用stopSelf()來結(jié)束服務(wù)昔案,因?yàn)樵创a里面自己實(shí)現(xiàn)了自動(dòng)關(guān)閉
- 默認(rèn)實(shí)現(xiàn)了onBind()返回的null尿贫,默認(rèn)實(shí)現(xiàn)的onStartCommand()的目的是將intent插入到工作隊(duì)列
總結(jié):使用IntentService的好處有哪些。首先爱沟,省去了手動(dòng)開線程的麻煩帅霜;第二匆背,不用手動(dòng)停止service呼伸;第三,由于設(shè)計(jì)了工作隊(duì)列,可以啟動(dòng)多次---startService(),但是只有一個(gè)service實(shí)例和一個(gè)工作線程括享。一個(gè)一個(gè)熟悉怒執(zhí)行搂根。
5,Service的生命周期
BroadcastReceiver面試詳解
1铃辖,廣播定義(類似觀察者模式)
BroadcastReceiver是一種全局監(jiān)聽器剩愧,用來實(shí)現(xiàn)系統(tǒng)中不同組件之間的通信。有時(shí)候也會(huì)用來作為傳輸少量而且發(fā)送頻率低的數(shù)據(jù)娇斩,但是如果數(shù)據(jù)的發(fā)送頻率比較高或者數(shù)量比較大就不建議用廣播接收者來接收了仁卷,因?yàn)檫@樣的效率很不好,因?yàn)锽roadcastReceiver接收數(shù)據(jù)的開銷還是比較大的犬第。
2锦积,使用場景
- 同一個(gè)app具有多個(gè)進(jìn)程的不同組件之間的消息通訊
- 不同app之間的組件之間消息通訊
eg:
1)App全局監(jiān)聽:在AndroidManifest中靜態(tài)注冊(cè)的廣播接收器,一般我們?cè)谑盏皆撓⒑笄干ぃ枰鲆恍┫鄳?yīng)的動(dòng)作丰介,而這些動(dòng)作與當(dāng)前App的組件,比如Activity或者Service的是否運(yùn)行無關(guān)鉴分,比如我們?cè)诩傻谌絇ush SDK時(shí)哮幢,一般都會(huì)添加一個(gè)靜態(tài)注冊(cè)的BroadcastReceiver來監(jiān)聽Push消息,當(dāng)有Push消息過來時(shí)志珍,會(huì)在后臺(tái)做一些網(wǎng)絡(luò)請(qǐng)求或者發(fā)送通知等等橙垢。
2)組件局部監(jiān)聽:這種主要是在Activity或者Service中使用registerReceiver()動(dòng)態(tài)注冊(cè)的廣播接收器,因?yàn)楫?dāng)我們收到一些特定的消息伦糯,比如網(wǎng)絡(luò)連接發(fā)生變化時(shí)钢悲,我們可能需要在當(dāng)前Activity頁面給用戶一些UI上的提示,或者將Service中的網(wǎng)絡(luò)請(qǐng)求任務(wù)暫停舔株。所以這種動(dòng)態(tài)注冊(cè)的廣播接收器適合特定組件的特定消息處理莺琳。
3,廣播的種類
- Normal Broadcast :Context.sendBroadcast 普通的廣播载慈,完全異步惭等,可以在同一時(shí)刻被所有接收者接收到,消息傳遞效率高且無法中斷廣播的傳播
- System Broadcast : Context.sendOrderedBroadcast 有序廣播办铡; 發(fā)送有序廣播后辞做,廣播接收者將按預(yù)先聲明的優(yōu)先級(jí)依次接收Broadcast。優(yōu)先級(jí)高的優(yōu)先接收到廣播寡具,而在其onReceiver()執(zhí)行過程中秤茅,廣播不會(huì)傳播到下一個(gè)接收者,此時(shí)當(dāng)前的廣播接收者可以abortBroadcast()來終止廣播繼續(xù)向下傳播童叠,也可以將intent中的數(shù)據(jù)進(jìn)行修改設(shè)置框喳,然后將其傳播到下一個(gè)廣播接收者课幕。 sendOrderedBroadcast(intent, null);//發(fā)送有序廣播
- 粘性廣播:sendStickyBroadcast()來發(fā)送該類型的廣播信息,這種的廣播的最大特點(diǎn)是五垮,當(dāng)粘性廣播發(fā)送后乍惊,最后的一個(gè)粘性廣播會(huì)滯留在操作系統(tǒng)中。如果在粘性廣播發(fā)送后的一段時(shí)間里放仗,如果有新的符合廣播的動(dòng)態(tài)注冊(cè)的廣播接收者注冊(cè)润绎,將會(huì)收到這個(gè)廣播消息,雖然這個(gè)廣播是在廣播接收者注冊(cè)之前發(fā)送的诞挨,另外一點(diǎn)莉撇,對(duì)于靜態(tài)注冊(cè)的廣播接收者來說,這個(gè)等同于普通廣播惶傻。
- Local Broadcast : 只在自身App內(nèi)傳播 本地廣播
4稼钩,實(shí)現(xiàn)廣播Receiver
靜態(tài)注冊(cè):注冊(cè)完成就一直運(yùn)行,Menifest文件中
動(dòng)態(tài)注冊(cè):跟隨Activity的生命周期达罗,必須要在onDestory中銷毀坝撑,否則內(nèi)存泄露,因?yàn)榭梢砸恢苯邮盏?/p>
5粮揉,內(nèi)部實(shí)現(xiàn)機(jī)制
自定義廣播接受者巡李,并復(fù)寫onRecvice方法
通過Binder機(jī)制向AMS(Activity Manager Service)進(jìn)行注冊(cè)
廣播發(fā)送者通過Binder機(jī)制向AMS發(fā)送廣播;
AMS查找符合相應(yīng)條件(IntentFilter/Permission等)的BroadcastReceiver扶认,將廣播相應(yīng)的消息循環(huán)隊(duì)列中
消息循環(huán)拿到廣播后侨拦,回調(diào)onReceive方法
6,本地廣播LocalBroadcastManager詳解
關(guān)于優(yōu)勢(shì):
- 使用它發(fā)送的廣播只能在自身的App內(nèi)傳播辐宾,不用擔(dān)心泄露隱私數(shù)據(jù)
- 其他App無法對(duì)你的App發(fā)送該廣播狱从,不用擔(dān)心安全漏洞
- 比系統(tǒng)全局廣播高效,為甚叠纹?系統(tǒng)廣播需要加入更多的廣播池季研,加載流程多
為何它高效
- 主要因?yàn)樗鼉?nèi)部是通過Handler實(shí)現(xiàn)的,它的sendBroadcast方法就是通過handler發(fā)送一個(gè)message實(shí)現(xiàn)的誉察。
- 系統(tǒng)廣播是通過Binder實(shí)現(xiàn)比handler要復(fù)雜低效与涡,用handler實(shí)現(xiàn)保障了其他應(yīng)用就無法向本應(yīng)用發(fā)廣播,而本應(yīng)用內(nèi)發(fā)廣播不會(huì)離開應(yīng)用本身
- 內(nèi)部協(xié)作靠2個(gè)Map集合持偏,mReceivers和mActions驼卖,當(dāng)然還有一個(gè)List集合mPendingBroadcast,主要就是存儲(chǔ)待接收的廣播對(duì)象
本地廣播可以用來做什么鸿秆? 比如酌畜,做一個(gè)殺不死的服務(wù)-監(jiān)聽火的App,比如微信卿叽,友盟和極光的廣播來啟動(dòng)自己
本地廣播是不能用靜態(tài)注冊(cè)的桥胞;靜態(tài)注冊(cè)的目的--程序停止后也能監(jiān)聽
Android中的動(dòng)畫
1恳守,幾種動(dòng)畫?
幀動(dòng)畫:指通過指定每一幀的圖片和播放時(shí)間埠戳,有序的進(jìn)行播放而形成動(dòng)畫效果,比如想聽的律動(dòng)條蕉扮。
補(bǔ)間動(dòng)畫:指通過指定View的初始狀態(tài)整胃、變化時(shí)間、方式喳钟,通過一系列的算法去進(jìn)行圖形變換屁使,從而形成動(dòng)畫效果,主要有Alpha奔则、Scale蛮寂、Translate、Rotate四種效果易茬。注意:只是在視圖層實(shí)現(xiàn)了動(dòng)畫效果酬蹋,并沒有真正改變View的屬性,比如滑動(dòng)列表抽莱,改變標(biāo)題欄的透明度范抓。
屬性動(dòng)畫:在Android3.0的時(shí)候才支持,通過不斷的改變View的屬性食铐,不斷的重繪而形成動(dòng)畫效果匕垫。相比于視圖動(dòng)畫,View的屬性是真正改變了虐呻。比如view的旋轉(zhuǎn)象泵,放大,縮小斟叼。
2偶惠,Android 動(dòng)畫框架實(shí)現(xiàn)原理
傳統(tǒng)的動(dòng)畫框架:View.startAnimation();
弊端:移動(dòng)后不能點(diǎn)擊。原因朗涩?跟實(shí)現(xiàn)機(jī)制有關(guān)系洲鸠。
所有的透明度、旋轉(zhuǎn)馋缅、平移扒腕、縮放動(dòng)畫,都是在view不斷刷新調(diào)用draw的情況下實(shí)現(xiàn)的萤悴。
調(diào)用的canvas.translate(xxx),canvas.scaleX(xxx)…. Xxx:matrix像素矩陣來控制動(dòng)畫的數(shù)據(jù)瘾腰。記得看源碼,結(jié)合多只縮放的demo看源碼覆履。
3蹋盆,屬性動(dòng)畫實(shí)現(xiàn)原理
工作原理:在一定時(shí)間間隔內(nèi)费薄,通過不斷對(duì)值進(jìn)行改變,并不斷將該值賦給對(duì)象的屬性栖雾,從而實(shí)現(xiàn)該對(duì)象在該屬性上的動(dòng)畫效果楞抡。
- ValueAnimator:通過不斷控制值的變化(初始值->結(jié)束值),將值手動(dòng)賦值給對(duì)象的屬性析藕,再不斷調(diào)用View的invalidate()方法召廷,去不斷onDraw重繪view,達(dá)到動(dòng)畫的效果账胧。
主要的三種方法:
a) ValueAnimator.ofInt(int values):估值器是整型估值器IntEaluator
b) ValueAnimator.ofFloat(float values):估值器是浮點(diǎn)型估值器FloatEaluator
c) ValueAnimator.ofObject(ObjectEvaluator, start, end):將初始值以對(duì)象的形式過渡到結(jié)束值竞慢,通過操作對(duì)象實(shí)現(xiàn)動(dòng)畫效果,需要實(shí)現(xiàn)Interpolator接口治泥,自定義估值器
估值器TypeEvalutor筹煮,設(shè)置動(dòng)畫如何從初始值過渡到結(jié)束值的邏輯。插值器(Interpolator)決定值的變化模式(勻速居夹、加速等);估值器(TypeEvalutor)決定值的具體變化數(shù)值败潦。
// 自定義估值器,需要實(shí)現(xiàn)TypeEvaluator接口
public class ObjectEvaluator implements TypeEvaluator{
// 復(fù)寫evaluate()准脂,在evaluate()里寫入對(duì)象動(dòng)畫過渡的邏輯
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) { // 參數(shù)說明
// fraction:表示動(dòng)畫完成度(根據(jù)它來計(jì)算當(dāng)前動(dòng)畫的值)
// startValue变屁、endValue:動(dòng)畫的初始值和結(jié)束值
...
// 寫入對(duì)象動(dòng)畫過渡的邏輯
return value;
// 返回對(duì)象動(dòng)畫過渡的邏輯計(jì)算后的值
} }
- ObjectAnimator:直接對(duì)對(duì)象的屬性值進(jìn)行改變操作,從而實(shí)現(xiàn)動(dòng)畫效果
ObjectAnimator繼承自ValueAnimator類意狠,底層的動(dòng)畫實(shí)現(xiàn)機(jī)制還是基本值的改變粟关。它是不斷控制值的變化,再不斷自動(dòng)賦給對(duì)象的屬性环戈,從而實(shí)現(xiàn)動(dòng)畫效果闷板。這里的自動(dòng)賦值,是通過調(diào)用對(duì)象屬性的set/get方法進(jìn)行自動(dòng)賦值院塞,屬性動(dòng)畫初始值如果有就直接取遮晚,沒有則調(diào)用屬性的get()方法獲取,當(dāng)值更新變化時(shí)拦止,通過屬性的set()方法進(jìn)行賦值县遣。每次賦值都是調(diào)用view的postInvalidate()/invalidate()方法不斷刷新視圖(實(shí)際調(diào)用了onDraw()方法進(jìn)行了重繪視圖)。
//Object 需要操作的對(duì)象汹族; propertyName 需要操作的對(duì)象的屬性萧求; values動(dòng)畫初始值&結(jié)束值,
//如果是兩個(gè)值顶瞒,則從a->b值過渡夸政,如果是三值,則從a->b->c
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String propertyName, float ...values);
如果采用ObjectAnimator類實(shí)現(xiàn)動(dòng)畫榴徐,操作的對(duì)象的屬性必須有g(shù)et()和set()方法守问。
其他用法:
1)AnimatorSet組合動(dòng)畫
AnimatorSet.play(Animator anim) :播放當(dāng)前動(dòng)畫
AnimatorSet.after(long delay) :將現(xiàn)有動(dòng)畫延遲x毫秒后執(zhí)行
AnimatorSet.with(Animator anim) :將現(xiàn)有動(dòng)畫和傳入的動(dòng)畫同時(shí)執(zhí)行
AnimatorSet.after(Animator anim) :將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之后執(zhí)行
AnimatorSet.before(Animator anim) : 將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之前執(zhí)行
- ViewPropertyAnimator直接對(duì)屬性操作匀归,View.animate()返回的是一個(gè)ViewPropertyAnimator對(duì)象,之后的調(diào)用方法都是基于該對(duì)象的操作耗帕,調(diào)用每個(gè)方法返回值都是它自身的實(shí)例
View.animate().alpha(0f).x(500).y(500).setDuration(500).setInterpolator()
3)設(shè)置動(dòng)畫監(jiān)聽
Animation.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animation animation) {//動(dòng)畫開始時(shí)執(zhí)行 }
@Override
public void onAnimationRepeat(Animation animation) {//動(dòng)畫重復(fù)時(shí)執(zhí)行 }
@Override
public void onAnimationCancel()(Animation animation) {//動(dòng)畫取消時(shí)執(zhí)行 }
@Override
public void onAnimationEnd(Animation animation) {//動(dòng)畫結(jié)束時(shí)執(zhí)行 }
});
4穆端,補(bǔ)間動(dòng)畫實(shí)現(xiàn)原理
主要有四種AlpahAnimation\ ScaleAnimation\ RotateAnimation\ TranslateAnimation四種,對(duì)透明度仿便、縮放体啰、旋轉(zhuǎn)、位移四種動(dòng)畫探越。
在調(diào)用View.startAnimation時(shí)狡赐,先調(diào)用View.setAnimation(Animation)方法給自己設(shè)置一個(gè)Animation對(duì)象窑业,再調(diào)用invalidate來重繪自己钦幔。在View.draw(Canvas, ViewGroup, long)方法中進(jìn)行了getAnimation(), 并調(diào)用了drawAnimation(ViewGroup, long, Animation, boolean)方法,此方法調(diào)用Animation.getTranformation()方法常柄,再調(diào)用applyTranformation()方法鲤氢,該方法中主要是對(duì)Transformation.getMatrix().setTranslate/setRotate/setAlpha/setScale來設(shè)置相應(yīng)的值,這個(gè)方法系統(tǒng)會(huì)以60FPS的頻率進(jìn)行調(diào)用西潘。
具體是在調(diào)Animation.start()方法中會(huì)調(diào)用animationHandler.start()方法卷玉,從而調(diào)用了scheduleAnimation()方法,這里會(huì)調(diào)用mChoreographer.postCallback(Choregrapher.CALLBACK_ANIMATION, this, null)放入事件隊(duì)列中喷市,等待doFrame()來消耗事件相种。
當(dāng)一個(gè) ChildView 要重畫時(shí),它會(huì)調(diào)用其成員函數(shù) invalidate() 函數(shù)將通知其 ParentView 這個(gè) ChildView 要重畫品姓,這個(gè)過程一直向上遍歷到 ViewRoot寝并,當(dāng) ViewRoot 收到這個(gè)通知后就會(huì)調(diào)用ViewRoot 中的 draw 函數(shù)從而完成繪制。View::onDraw() 有一個(gè)畫布參數(shù) Canvas, 畫布顧名思義就是畫東西的地方腹备,Android 會(huì)為每一個(gè) View 設(shè)置好畫布衬潦,View 就可以調(diào)用 Canvas 的方法,比如:drawText, drawBitmap, drawPath 等等去畫內(nèi)容植酥。每一個(gè) ChildView 的畫布是由其 ParentView 設(shè)置的镀岛,ParentView 根據(jù) ChildView 在其內(nèi)部的布局來調(diào)整 Canvas,其中畫布的屬性之一就是定義和 ChildView 相關(guān)的坐標(biāo)系友驮,默認(rèn)是橫軸為 X 軸漂羊,從左至右,值逐漸增大卸留,豎軸為 Y 軸拨与,從上至下,值逐漸增大艾猜。
Android 補(bǔ)間動(dòng)畫就是通過 ParentView 來不斷調(diào)整 ChildView 的畫布坐標(biāo)系來實(shí)現(xiàn)的买喧,在ParentView的dispatchDraw方法會(huì)被調(diào)用捻悯。
dispatchDraw() {
....
Animation a = ChildView.getAnimation()
Transformation tm = a.getTransformation();
Use tm to set ChildView's Canvas; Invalidate();
....
}
這里有兩個(gè)類:Animation 和 Transformation,這兩個(gè)類是實(shí)現(xiàn)動(dòng)畫的主要的類淤毛,Animation 中主要定義了動(dòng)畫的一些屬性比如開始時(shí)間今缚、持續(xù)時(shí)間、是否重復(fù)播放等低淡,這個(gè)類主要有兩個(gè)重要的函數(shù):getTransformation 和 applyTransformation姓言,在 getTransformation 中 Animation 會(huì)根據(jù)動(dòng)畫的屬性來產(chǎn)生一系列的差值點(diǎn),然后將這些差值點(diǎn)傳給 applyTransformation蔗蹋,這個(gè)函數(shù)將根據(jù)這些點(diǎn)來生成不同的 Transformation何荚,Transformation 中包含一個(gè)矩陣和 alpha 值,矩陣是用來做平移猪杭、旋轉(zhuǎn)和縮放動(dòng)畫的餐塘,而 alpha 值是用來做 alpha 動(dòng)畫的(簡單理解的話,alpha 動(dòng)畫相當(dāng)于不斷變換透明度或顏色來實(shí)現(xiàn)動(dòng)畫)皂吮,調(diào)用 dispatchDraw 時(shí)會(huì)調(diào)用 getTransformation 來得到當(dāng)前的 Transformation戒傻。某一個(gè) View 的動(dòng)畫的繪制并不是由他自己完成的而是由它的父 view 完成。
1)補(bǔ)間動(dòng)畫TranslateAnimation,View位置移動(dòng)了蜂筹,可是點(diǎn)擊區(qū)域還在原來的位置需纳,為什么?
View在做動(dòng)畫是艺挪,根據(jù)動(dòng)畫時(shí)間的插值不翩,計(jì)算出一個(gè)Matrix,不停的invalidate麻裳,在onDraw中的Canvas上使用這個(gè)計(jì)算出來的Matrix去draw view的內(nèi)容口蝠。某個(gè)view的動(dòng)畫繪制并不是由它自己完成,而是由它的父view完成掂器,使它的父view畫布進(jìn)行了移動(dòng)亚皂,而點(diǎn)擊時(shí)還是點(diǎn)擊原來的畫布。使得它看起來變化了国瓮。
數(shù)據(jù)庫面試相關(guān)
1灭必,數(shù)據(jù)庫的操作類有那些,如何導(dǎo)入外部數(shù)據(jù)庫乃摹?
讀懂題目禁漓。如果碰到問題比較模糊的時(shí)候可以適當(dāng)問問面試官。
配合面試官來面試:面試是一個(gè)相互了解的過程孵睬,要充分利用面試的題目和時(shí)間把自己的能力和技術(shù)展現(xiàn)出來播歼,面試官能夠看到你的真實(shí)技術(shù)。
1) 使用數(shù)據(jù)庫的方式有哪些?
(1) openOrCreateDatabase(String path);
(2) 繼承SqliteOpenHelper類對(duì)數(shù)據(jù)庫及其版本進(jìn)行管理(onCreate,onUpgrade)
當(dāng)在程序當(dāng)中調(diào)用這個(gè)類的方法getWritableDatabase()或者getReadableDatabase();的時(shí)候才會(huì)打開數(shù)據(jù)庫秘狞。如果當(dāng)時(shí)沒有數(shù)據(jù)庫文件的時(shí)候叭莫,系統(tǒng)就會(huì)自動(dòng)生成一個(gè)數(shù)據(jù)庫。
2) 操作的類型:增刪改查CRUD
直接操作SQL語句:SQliteDatabase.execSQL(sql);
面向?qū)ο蟮牟僮鞣绞剑篠QLiteDatabase.insert(table, nullColumnHack, ContentValues);
如何導(dǎo)入外部數(shù)據(jù)庫烁试?
一般外部數(shù)據(jù)庫文件可能放在SD卡或者res/raw或者assets目錄下面雇初。
寫一個(gè)DBManager的類來管理,數(shù)據(jù)庫文件搬家减响,先把數(shù)據(jù)庫文件復(fù)制到”/data/data/包名/databases/”目錄下面靖诗,然后通過db.openOrCreateDatabase(db文件),打開數(shù)據(jù)庫使用聘萨。
我上一個(gè)項(xiàng)目就是這么做的谭确,由于app上架之前就有一些初始數(shù)據(jù)需要內(nèi)置,也會(huì)碰到數(shù)據(jù)的升級(jí)等問題主之,我是這么做的…… 同時(shí)我碰到最有意思的問題就是關(guān)于數(shù)據(jù)庫并發(fā)操作的問題颂鸿,比如:多線程操作數(shù)據(jù)庫的時(shí)候促绵,我采取的是封裝使用互斥鎖來解決……
Webview面試詳解
1,常見的坑
- android api 16以及以前的版本存在遠(yuǎn)程代碼執(zhí)行安全漏洞据途,主要是因?yàn)槌绦驔]有正確的限制使用Webview.addJavascriptInterface方法绞愚,
遠(yuǎn)程攻擊者可以通過使用Java Reflection Api利用該漏洞執(zhí)行任意Java對(duì)象的方法叙甸,16后面的版本改了之后申明@JavascriptInterace注解就可以了
- Webview在布局文件中的使用颖医,webvew卸載其他容器中時(shí)
- JsBridge ,調(diào)用原生相互通訊
- webviewClient.onPageFinished(會(huì)跳轉(zhuǎn)其他url的時(shí)候不斷調(diào)用) -> WebChromeClient.onProgressChanged(優(yōu)先調(diào)用)
- 后臺(tái)耗電(需要在onDestory里把webview 銷毀掉)
- Webview硬件加速導(dǎo)致頁面渲染問題裆蒸;只能通過暫時(shí)關(guān)閉加速
2熔萧,內(nèi)存泄露問題
- 獨(dú)立進(jìn)程,涉及到了進(jìn)程間的通訊(推薦)
- 動(dòng)態(tài)添加webview僚祷,對(duì)傳入的webview中使用的Context使用弱引用佛致,動(dòng)態(tài)添加webview意思在布局創(chuàng)建個(gè)ViewGroup用來放置Webview,Activity創(chuàng)建時(shí)add進(jìn)來辙谜,在Activity停止時(shí)remove掉
Binder面試詳解
1俺榆,Binder機(jī)制的簡單理解
在Android系統(tǒng)的Binder機(jī)制中,是有Client,Service,ServiceManager,Binder驅(qū)動(dòng)程序組成的装哆,其中Client罐脊,service,Service Manager運(yùn)行在用戶空間蜕琴,Binder驅(qū)動(dòng)程序是運(yùn)行在內(nèi)核空間的萍桌。而Binder就是把這4種組件粘合在一塊的粘合劑,其中核心的組件就是Binder驅(qū)動(dòng)程序凌简,Service Manager提供輔助管理的功能上炎,而Client和Service正是在Binder驅(qū)動(dòng)程序和Service Manager提供的基礎(chǔ)設(shè)施上實(shí)現(xiàn)C/S 之間的通信。其中Binder驅(qū)動(dòng)程序提供設(shè)備文件/dev/binder與用戶控件進(jìn)行交互雏搂,
Client藕施、Service寇损,Service Manager通過open和ioctl文件操作相應(yīng)的方法與Binder驅(qū)動(dòng)程序進(jìn)行通信。而Client和Service之間的進(jìn)程間通信是通過Binder驅(qū)動(dòng)程序間接實(shí)現(xiàn)的裳食。而Binder Manager是一個(gè)守護(hù)進(jìn)程润绵,用來管理Service,并向Client提供查詢Service接口的能力胞谈。
2尘盼,為什么使用Binder(已有的跨進(jìn)程都不適合Android)
- Android使用的Linux內(nèi)核擁有非常多的跨進(jìn)程通訊機(jī)制(管道,消息隊(duì)列烦绳,信號(hào)卿捎,信號(hào)量,共享內(nèi)存径密,socket )
擴(kuò)展:https://blog.csdn.net/qq_26626709/article/details/52206067)
- 性能 (相對(duì)Socket更高效)
- 安全(跟socket的只一個(gè)url就鏈接的不安全相比午阵,binder支持雙方做調(diào)用時(shí)身份校驗(yàn))
3,binder通信模型
通訊錄享扔,serviceManager底桂,binder驅(qū)動(dòng)(類似電話基站)
怎么調(diào)用?(SM = ServiceManager)
先去serviceManager注冊(cè)一個(gè)方法惧眠,然后通過binder驅(qū)動(dòng)來轉(zhuǎn)換成代理對(duì)象返回給客戶端完成注冊(cè)籽懦。
4,到底什么是Binder氛魁?
通常意義下暮顺,Binder指的是一種通信機(jī)制
對(duì)于Server進(jìn)程來說,Binder指的是Binder本地對(duì)象
對(duì)于Client來說秀存,Binder指的是Binder代理對(duì)象
對(duì)于傳輸過程而言捶码,Binder是可以進(jìn)行垮進(jìn)程傳遞的對(duì)象
Android中實(shí)現(xiàn)IBinder這個(gè)接口就可以垮進(jìn)程使用
5,AIDL解決了什么問題或链?
AIDL的全稱:Android Interface Definition Language惫恼,安卓接口定義語言。
由于Android系統(tǒng)中的進(jìn)程之間不能共享內(nèi)存澳盐,所以需要提供一些機(jī)制在不同的進(jìn)程之間進(jìn)行數(shù)據(jù)通信祈纯。
遠(yuǎn)程過程調(diào)用:RPC—Remote Procedure Call。 安卓就是提供了一種IDL的解決方案來公開自己的服務(wù)接口洞就。
AIDL:可以理解為雙方的一個(gè)協(xié)議合同盆繁。雙方都要持有這份協(xié)議---文本協(xié)議 xxx.aidl文件
(安卓內(nèi)部編譯的時(shí)候會(huì)將aidl協(xié)議翻譯生成一個(gè)xxx.java文件---代理模式:Binder驅(qū)動(dòng)有關(guān)的,Linux底層通訊有關(guān)的旬蟋。)
在系統(tǒng)源碼里面有大量用到aidl油昂,比如系統(tǒng)服務(wù)。電視機(jī)頂盒系統(tǒng)開發(fā)。你的服務(wù)要暴露給別的開發(fā)者來使用冕碟。
6拦惋,Android開發(fā)中何時(shí)使用多進(jìn)程?使用多進(jìn)程的好處是什么安寺?
即時(shí)通訊或者社交應(yīng)用厕妖,webview可以單獨(dú)給進(jìn)程
在啟動(dòng)一個(gè)不可見的輕量級(jí)私有進(jìn)程,在后臺(tái)收發(fā)消息挑庶,或者做一些耗時(shí)的事情言秸,或者開機(jī)啟動(dòng)這個(gè)進(jìn)程,然后做監(jiān)聽等迎捺。還有就是防止主進(jìn)程被殺守護(hù)進(jìn)程举畸,守護(hù)進(jìn)程和主進(jìn)程之間相互監(jiān)視,有一方被殺就重新啟動(dòng)它凳枝。
7抄沮,Android中進(jìn)程間通信有那些實(shí)現(xiàn)方式?
Intent岖瑰,Binder(AIDL)叛买,Messenger,BroadcastReceiver
8蹋订,binder的內(nèi)存拷貝過程
相比其他的IPC通信率挣,比如消息機(jī)制、共享內(nèi)存辅辩、管道难礼、信號(hào)量等娃圆,Binder僅需一次內(nèi)存拷貝玫锋,即可讓目標(biāo)進(jìn)程讀取到更新數(shù)據(jù),同共享內(nèi)存一樣相當(dāng)高效讼呢,其他的IPC通信機(jī)制大多需要2次內(nèi)存拷貝撩鹿。Binder內(nèi)存拷貝的原理為:進(jìn)程A為Binder客戶端,在IPC調(diào)用前悦屏,需將其用戶空間的數(shù)據(jù)拷貝到Binder驅(qū)動(dòng)的內(nèi)核空間节沦,由于進(jìn)程B在打開Binder設(shè)備(/dev/binder)時(shí),已將Binder驅(qū)動(dòng)的內(nèi)核空間映射(mmap)到自己的進(jìn)程空間础爬,所以進(jìn)程B可以直接看到Binder驅(qū)動(dòng)內(nèi)核空間的內(nèi)容改動(dòng)
Handler和AsyncTask面試詳解
1甫贯,什么是Handler?
Handler是線程的消息通訊的橋梁看蚜,主要用來發(fā)送消息及處理消息叫搁。
handler通過發(fā)送和處理Message和Runnable對(duì)象來關(guān)聯(lián)相對(duì)應(yīng)線程的MessageQueue
- 可以讓對(duì)應(yīng)的Message和Runnable在未來的某個(gè)時(shí)間點(diǎn)進(jìn)行相應(yīng)處理
- 讓自己想要處理的耗時(shí)操作放在子線程,讓更新UI的操作放在主線程
2,Handler的使用方法
- post(Runnable)其實(shí)底層調(diào)用的還是sendMessage渴逻,主要是系統(tǒng)自己封裝了
- sendMessage(message)
3疾党,Handler機(jī)制原理
handler,它的作用就是實(shí)現(xiàn)線程之間的通信惨奕。
handler整個(gè)流程中雪位,主要有四個(gè)對(duì)象,handler梨撞,Message,MessageQueue,Looper雹洗。當(dāng)應(yīng)用創(chuàng)建的時(shí)候,就會(huì)在主線程中創(chuàng)建handler對(duì)象卧波,
我們通過要傳送的消息保存到Message中队伟,handler通過調(diào)用sendMessage方法將Message發(fā)送到MessageQueue中,Looper對(duì)象就會(huì)不斷的調(diào)用loop()方法
不斷的從MessageQueue中取出Message交給handler進(jìn)行處理幽勒。從而實(shí)現(xiàn)線程之間的通信嗜侮。
4,解決Handler的內(nèi)存泄露
原因:靜態(tài)內(nèi)部類持有外部類的匿名引用啥容,導(dǎo)致外部activity無法釋放
解決:handler內(nèi)部持有外部activity的弱引用锈颗,并把handler改為靜態(tài)內(nèi)部類,mHandler.removeCallback
5咪惠,什么是AsyncTask
本質(zhì)上就是一個(gè)封裝了線程池和handler的異步框架击吱,無法做耗時(shí)操作
怎么使用:三個(gè)參數(shù)(),5個(gè)方法(onPreExecute前期操作遥昧,doInBackground覆醇,onPostExecute)
6,AsyncTask的機(jī)制原理
它本質(zhì)上是一個(gè)靜態(tài)的線程池炭臭,它派生出來的子類可以實(shí)現(xiàn)不同的異步任務(wù)永脓,這些任務(wù)都是提交到靜態(tài)的線程池中執(zhí)行。
線程池中的工作線程執(zhí)行doInBackground(mParams)方法執(zhí)行異步任務(wù)
當(dāng)任務(wù)狀態(tài)改變之后鞋仍,工作線程會(huì)向UI線程發(fā)送消息常摧,AsyncTask內(nèi)部的InternalHandler想要這些消息,并調(diào)用相關(guān)的回調(diào)函數(shù)
7威创,AsyncTask的注意事項(xiàng)
內(nèi)存泄露:跟handler一樣
生命周期:不調(diào)用cancel落午,無法銷毀,可能導(dǎo)致崩潰
8肚豺,HandlerThread面試詳解溃斋,背景,它是什么吸申,有什么優(yōu)缺點(diǎn)梗劫?
開啟Thread子線程進(jìn)行耗時(shí)操作寞奸,多次創(chuàng)建和銷毀線程是很耗系統(tǒng)資源的,為了解決這個(gè)問題在跳,google搞了一個(gè)HandlerThread枪萄;
它就是一個(gè)線程類,繼承了Thread猫妙,有內(nèi)部Looper對(duì)象瓷翻,可以進(jìn)行l(wèi)ooper循環(huán),通過獲取HandlerThread的looper對(duì)象傳遞給Handler對(duì)象割坠,
可以在handlerMessage方法中執(zhí)行異步任務(wù)齐帚。
- 優(yōu)點(diǎn):不會(huì)有堵塞,減少了性能的消耗
- 缺陷:不能同時(shí)進(jìn)行多任務(wù)的處理彼哼,需要等待对妄,處理效率低
與線程池注重并發(fā)不同,HandlerThread是一個(gè)串行隊(duì)列敢朱,HandlerThread背后只有一個(gè)線程剪菱。
9,HandlerThread源碼解析
10拴签,Handler孝常、 Thread 和 HandlerThread 的差別
View 的繪制與分發(fā),自定義等
1蚓哩,view樹的繪制流程
measure( 測量大泄咕摹)-> layout(安置位置)-> draw (繪制)自上而下進(jìn)行遍歷
2,measure的重要方法
View的measure過程由ViewGroup傳遞而來岸梨,在調(diào)用View.measure方法之前喜颁,會(huì)首先根據(jù)View自身的LayoutParams和父布局的MeasureSpec確定子view的MeasureSpec,然后將view寬高對(duì)應(yīng)的measureSpec傳遞到measure方法中曹阔,那么子view的MeasureSpec獲取規(guī)則是怎樣的半开?分幾種情況進(jìn)行說明
-
父布局是EXACTLY模式:
a.子view寬或高是個(gè)確定值,那么子view的size就是這個(gè)確定值次兆,mode是EXACTLY(是不是說子view寬高可以超過父view稿茉?見下一個(gè))
b.子view寬或高設(shè)置為match_parent,那么子view的size就是占滿父容器剩余空間,模式就是EXACTLY
c.子view寬或高設(shè)置為wrap_content,那么子view的size就是占滿父容器剩余空間芥炭,不能超過父容器大小,模式就是AT_MOST
父布局是AT_MOST模式:
a.子view寬或高是個(gè)確定值恃慧,那么子view的size就是這個(gè)確定值园蝠,mode是EXACTLY
b.子view寬或高設(shè)置為match_parent,那么子view的size就是占滿父容器剩余空間,不能超過父容器大小,模式就是AT_MOST
c.子view寬或高設(shè)置為wrap_content,那么子view的size就是占滿父容器剩余空間痢士,不能超過父容器大小彪薛,模式就是AT_MOST
- 父布局是UNSPECIFIED模式:
a.子view寬或高是個(gè)確定值茂装,那么子view的size就是這個(gè)確定值,mode是EXACTLY
b.子view寬或高設(shè)置為match_parent,那么子view的size就是0善延,模式就是UNSPECIFIED
c.子view寬或高設(shè)置為wrap_content,那么子view的size就是0少态,模式就是UNSPECIFIED
獲取到寬高的MeasureSpec后,傳入view的measure方法中來確定view的寬高易遣,這個(gè)時(shí)候還要分情況
1.當(dāng)MeasureSpec的mode是UNSPECIFIED,此時(shí)view的寬或者高要看view有沒有設(shè)置背景彼妻,如果沒有設(shè)置背景,就返回設(shè)置的minWidth或minHeight,這兩個(gè)值如果沒有設(shè)置默認(rèn)就是0豆茫,如果view設(shè)置了背景侨歉,就取minWidth或minHeight和背景這個(gè)drawable固有寬或者高中的最大值返回
2.當(dāng)MeasureSpec的mode是AT_MOST和EXACTLY,此時(shí)view的寬高都返回從MeasureSpec中獲取到的size值揩魂,這個(gè)值的確定見上邊的分析幽邓。因此如果要通過繼承view實(shí)現(xiàn)自定義view,一定要重寫onMeasure方法對(duì)wrap_conten屬性做處理火脉,否則牵舵,他的match_parent和wrap_content屬性效果就是一樣的
measure(ViewGroup.LayoutParams,MeasureSpec測量規(guī)格倦挂,如何測量棋枕,三種模式(父容器,固定大小妒峦,子容器))
- UNSPECIFIED:不對(duì)View大小做限制重斑,如:ListView,ScrollView
- EXACTLY:確切的大小肯骇,如:100dp或者march_parent
- AT_MOST:大小不可超過某數(shù)值窥浪,如:wrap_content
onMeasure(2個(gè)參數(shù),寬和高)
setMeasuredDimension(設(shè)置測量的大小笛丙,一定會(huì)調(diào)用漾脂,寬和高)
3,layout方法
view中的onLayout方法是抽象方法胚鸯,viewgroup繼承view必須實(shí)現(xiàn)onLayout方法
layout方法的作用是用來確定view本身的位置骨稿,onLayout方法用來確定所有子元素的位置,當(dāng)ViewGroup的位置確定之后姜钳,它在onLayout中會(huì)遍歷所有的子元素并調(diào)用其layout方法坦冠,在子元素的layout方法中onLayout方法又會(huì)被調(diào)用。layout方法的流程是哥桥,首先通過setFrame方法確定view四個(gè)頂點(diǎn)的位置辙浑,然后view在父容器中的位置也就確定了,接著會(huì)調(diào)用onLayout方法拟糕,確定子元素的位置判呕,onLayout是個(gè)空方法倦踢,需要繼承者去實(shí)現(xiàn)。
getMeasuredHeight和getHeight方法有什么區(qū)別侠草?getMeasuredHeight(測量高度)形成于view的measure過程辱挥,getHeight(最終高度)形成于layout過程,在有些情況下边涕,view需要measure多次才能確定測量寬高晤碘,在前幾次的測量過程中,得出的測量寬高有可能和最終寬高不一致奥吩,但是最終來說哼蛆,還是會(huì)相同,有一種情況會(huì)導(dǎo)致兩者值不一樣霞赫,如下腮介,此代碼會(huì)導(dǎo)致view的最終寬高比測量寬高大100px
public void layout(int l,int t,int r, int b){
super.layout(l,t,r+100,b+100);
}
4,draw
View的繪制過程遵循如下幾步:
a.繪制背景 background.draw(canvas)
b.繪制自己(onDraw)
c.繪制children(dispatchDraw)
d.繪制裝飾(onDrawScrollBars)
View繪制過程的傳遞是通過dispatchDraw來實(shí)現(xiàn)的端衰,它會(huì)遍歷所有的子元素的draw方法叠洗,如此draw事件就一層一層的傳遞下去了
ps:view有一個(gè)特殊的方法setWillNotDraw,如果一個(gè)view不需要繪制內(nèi)容旅东,即不需要重寫onDraw方法繪制灭抑,可以開啟這個(gè)標(biāo)記,系統(tǒng)會(huì)進(jìn)行相應(yīng)的優(yōu)化抵代。默認(rèn)情況下腾节,View沒有開啟這個(gè)標(biāo)記,默認(rèn)認(rèn)為需要實(shí)現(xiàn)onDraw方法繪制荤牍,當(dāng)我們繼承ViewGroup實(shí)現(xiàn)自定義控件案腺,并且明確知道不需要具備繪制功能時(shí),可以開啟這個(gè)標(biāo)記康吵,如果我們重寫了onDraw,那么要顯示的關(guān)閉這個(gè)標(biāo)記
子view寬高可以超過父view劈榨?能
1.android:clipChildren = "false" 這個(gè)屬性要設(shè)置在父 view 上。代表其中的子View 可以超出屏幕晦嵌。
2.子view 要有具體的大小同辣,一定要比父view 大 才能超出。比如 父view 高度 100px 子view 設(shè)置高度150px惭载。子view 比父view大旱函,這樣超出的屬性才有意義。(高度可以在代碼中動(dòng)態(tài)賦值棕兼,但不能用wrap_content / match_partent)陡舅。
3.對(duì)父布局還有要求,要求使用linearLayout(反正我用RelativeLayout 是不行)伴挚。你如果必須用其他布局可以在需要超出的view上面套一個(gè)linearLayout 外面再套其他的布局靶衍。
4.最外面的布局如果設(shè)置的padding 不能超出
5,自定義view需要注意的幾點(diǎn)
1.讓view支持wrap_content屬性茎芋,在onMeasure方法中針對(duì)AT_MOST模式做專門處理颅眶,否則wrap_content會(huì)和match_parent效果一樣(繼承ViewGroup也同樣要在onMeasure中做這個(gè)判斷處理)
if(widthMeasureSpec == MeasureSpec.AT_MOST && heightMeasureSpec == MeasureSpec.AT_MOST){
setMeasuredDimension(200,200); // wrap_content情況下要設(shè)置一個(gè)默認(rèn)值,最終的值需要計(jì)算得到剛好包裹內(nèi)容的寬高值
}else if(widthMeasureSpec == MeasureSpec.AT_MOST){
setMeasuredDimension(200,heightMeasureSpec );
}else if(heightMeasureSpec == MeasureSpec.AT_MOST){
setMeasuredDimension(heightMeasureSpec ,200);
}
2.讓view支持padding(onDraw的時(shí)候田弥,寬高減去padding值涛酗,margin由父布局控制,不需要view考慮)偷厦,自定義ViewGroup需要考慮自身的padding和子view的margin造成的影響
3.在view中盡量不要使用handler商叹,使用view本身的post方法
4.在onDetachedFromWindow中及時(shí)停止線程或動(dòng)畫
5.view帶有滑動(dòng)嵌套情形時(shí),處理好滑動(dòng)沖突
擴(kuò)展:優(yōu)化自定義view
減少在onDraw里面大量計(jì)算和對(duì)象創(chuàng)建只泼,大量內(nèi)存分配
盡量少用invalidate()次數(shù)
view里面耗時(shí)的操作layout剖笙,減少requestLayout()避免讓UI系統(tǒng)重新遍歷整棵樹
如果有一個(gè)很復(fù)雜的布局,不如將這個(gè)復(fù)雜的布局直接使用自己寫的viewgroup來實(shí)現(xiàn)请唱,減少了一個(gè)樹的層次關(guān)系弥咪,全部都是自己測量和layout,打到優(yōu)化的目的十绑,facebook經(jīng)常這么搞
6聚至,介紹下實(shí)現(xiàn)一個(gè)自定義view的基本流程
1、自定義View的屬性 編寫attr.xml文件
2本橙、在layout布局文件中引用扳躬,同時(shí)引用命名空間
3、在View的構(gòu)造方法中獲得我們自定義的屬性 甚亭,在自定義控件中進(jìn)行讀却摇(構(gòu)造方法拿到attr.xml文件值)
4、重寫onMesure
5狂鞋、重寫onDraw
7片择,View的事件分發(fā)機(jī)制
1,為什么有事件分發(fā)機(jī)制骚揍?
view是樹形結(jié)構(gòu)的字管,view會(huì)重疊,點(diǎn)擊會(huì)無法判斷信不,所以需要事件分發(fā)來統(tǒng)一調(diào)度
2嘲叔,三個(gè)重要的事件分發(fā)方法?
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
3抽活,事件分發(fā)流程
Activity->PhoneWindow->DecorView->ViewGroup->View
如果事件沒有被攔截硫戈,就拋給Activity
1、Touch事件傳遞的相關(guān)API有dispatchTouchEvent下硕、onTouchEvent丁逝、onInterceptTouchEvent
2汁胆、Touch事件相關(guān)的類有View、ViewGroup霜幼、Activity
3嫩码、Touch事件會(huì)被封裝成MotionEvent對(duì)象,該對(duì)象封裝了手勢(shì)按下罪既、移動(dòng)铸题、松開等動(dòng)作
4、Touch事件通常從Activity#dispatchTouchEvent發(fā)出琢感,只要沒有被消費(fèi)丢间,會(huì)一直往下傳遞,到最底層的View驹针。
5烘挫、如果Touch事件傳遞到的每個(gè)View都不消費(fèi)事件,那么Touch事件會(huì)反向向上傳遞,最終交由Activity#onTouchEvent處理.
6牌捷、onInterceptTouchEvent為ViewGroup特有墙牌,可以攔截事件.
7、Down事件到來時(shí)暗甥,如果一個(gè)View沒有消費(fèi)該事件喜滨,那么后續(xù)的MOVE/UP事件都不會(huì)再給它
8,View的加載流程
View隨著Activity的創(chuàng)建而加載撤防,startActivity啟動(dòng)一個(gè)Activity時(shí)虽风,在ActivityThread的handleLaunchActivity方法中會(huì)執(zhí)行Activity的onCreate方法,這個(gè)時(shí)候會(huì)調(diào)用setContentView加載布局創(chuàng)建出DecorView并將我們的layout加載到DecorView中寄月,當(dāng)執(zhí)行到handleResumeActivity時(shí)辜膝,Activity的onResume方法被調(diào)用,然后WindowManager會(huì)將DecorView設(shè)置給ViewRootImpl,這樣漾肮,DecorView就被加載到Window中了厂抖,此時(shí)界面還沒有顯示出來,還需要經(jīng)過View的measure克懊,layout和draw方法忱辅,才能完成View的工作流程。我們需要知道View的繪制是由ViewRoot來負(fù)責(zé)的谭溉,每一個(gè)DecorView都有一個(gè)與之關(guān)聯(lián)的ViewRoot,這種關(guān)聯(lián)關(guān)系是由WindowManager維護(hù)的墙懂,將DecorView和ViewRoot關(guān)聯(lián)之后,ViewRootImpl的requestLayout會(huì)被調(diào)用以完成初步布局扮念,通過scheduleTraversals方法向主線程發(fā)送消息請(qǐng)求遍歷损搬,最終調(diào)用ViewRootImpl的performTraversals方法,這個(gè)方法會(huì)執(zhí)行View的measure layout 和draw流程
9,View的滑動(dòng)方式
a.layout(left,top,right,bottom):通過修改View四個(gè)方向的屬性值來修改View的坐標(biāo)巧勤,從而滑動(dòng)View
b.offsetLeftAndRight() offsetTopAndBottom():指定偏移量滑動(dòng)view
c.LayoutParams,改變布局參數(shù):layoutParams中保存了view的布局參數(shù)嵌灰,可以通過修改布局參數(shù)的方式滑動(dòng)view
d.通過動(dòng)畫來移動(dòng)view:注意安卓的平移動(dòng)畫不能改變view的位置參數(shù),屬性動(dòng)畫可以
e.scrollTo/scrollBy:注意移動(dòng)的是view的內(nèi)容踢关,scrollBy(50,50)你會(huì)看到屏幕上的內(nèi)容向屏幕的左上角移動(dòng)了伞鲫,這是參考對(duì)象不同導(dǎo)致的粘茄,你可以看作是它移動(dòng)的是手機(jī)屏幕签舞,手機(jī)屏幕向右下角移動(dòng),那么屏幕上的內(nèi)容就像左上角移動(dòng)了
f.scroller:scroller需要配置computeScroll方法實(shí)現(xiàn)view的滑動(dòng)柒瓣,scroller本身并不會(huì)滑動(dòng)view儒搭,它的作用可以看作一個(gè)插值器,它會(huì)計(jì)算當(dāng)前時(shí)間點(diǎn)view應(yīng)該滑動(dòng)到的距離芙贫,然后view不斷的重繪搂鲫,不斷的調(diào)用computeScroll方法,這個(gè)方法是個(gè)空方法磺平,所以我們重寫這個(gè)方法魂仍,在這個(gè)方法中不斷的從scroller中獲取當(dāng)前view的位置,調(diào)用scrollTo方法實(shí)現(xiàn)滑動(dòng)的效果
10. Requestlayout拣挪, onlayout擦酌, onDraw, DrawChild 區(qū)別與聯(lián)系
RequestLayout()方法:會(huì)導(dǎo)致調(diào)用Measure()方法和layout()菠劝。將會(huì)根據(jù)標(biāo)志位判斷是否需要onDraw();
說明:只是對(duì)View樹重新布局layout過程包括measure()和layout()過程赊舶,如果view的l,t,r,b沒有必變,那就不會(huì)觸發(fā)onDraw赶诊;但是如果這次刷新是在動(dòng)畫 里笼平,mDirty非空,就會(huì)導(dǎo)致onDraw舔痪。
onLayout():擺放viewGroup里面的子控件
onDraw():繪制視圖本身寓调;(每個(gè)View都需要重載該方法,ViewGroup不需要實(shí)現(xiàn)該方法)
drawChild(): 重新回調(diào)每一個(gè)子視圖的draw方法锄码。child.draw(canvas, this, drawingTime);
11. invalidate()和 postInvalidate() 的區(qū)別及使用
View.invalidate():層層上傳到父級(jí)夺英,直到傳遞到ViewRootImpl后出發(fā)了scheduleTraversals(),然后整個(gè)View樹開始重新按照View繪制流程進(jìn)行重繪任務(wù)。
invalidate():在UI主線程當(dāng)中刷新View巍耗;
postInvalidate():在子線程當(dāng)中刷新View秋麸;其實(shí)最終調(diào)用的就是invalidate,原理依然是通過工作線程向主線程發(fā)送消息這一機(jī)制炬太。
View.postInvalidate最終會(huì)調(diào)用ViewRootImpl.dispatchInvalidateDelayed()
public void postInvalidate() {
postInvalidateDelayed(0);
}
public void postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this,delayMilliseconds);
}
}
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
mHandler.sendMessageDelayed(msg, delayMilliseconds);
//這里的mHandler是ViewRootHandler實(shí)例灸蟆,在該Handler的handleMessage方法中調(diào)用了view.invalidate()方法。
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INVALIDATE:
((View) msg.obj).invalidate();
break;
}
}
12,LinearLayout對(duì)比RelativeLayout
性能對(duì)比:LinearLayout的性能要比RelativeLayout好炒考。
因?yàn)镽elativeLayout會(huì)測量兩次可缚。而默認(rèn)情況下(沒有設(shè)置weight)LinearLayout只會(huì)測量一次。
為什么RelativeLayout會(huì)測量兩次斋枢?首先RelativeLayout中的子view排列方式是基于彼此依賴的關(guān)系帘靡,而這個(gè)依賴可能和布局中view的順序無關(guān),在確定每一個(gè)子view的位置的時(shí)候瓤帚,就需要先給每一個(gè)子view排一下序描姚。又因?yàn)镽elativeLayout允許橫向和縱向相互依賴,所以需要橫向縱向分別進(jìn)行一次排序測量戈次。
13轩勘,RecyclerView在很多方面能取代ListView,Google為什么沒把ListView劃上一條過時(shí)的橫線怯邪?
ListView采用的是RecyclerBin的回收機(jī)制在一些輕量級(jí)的List顯示時(shí)效率更高绊寻。
14, RecyclerView 的緩存機(jī)制
四級(jí)緩存悬秉,主要三個(gè)類(Recycler澄步,RecycledViewPool和ViewCacheExtension)
Recycler:管理已經(jīng)廢棄或者與RecyclerView分離的ViewHolder,里面有2個(gè)重要的成員
mAttachedScrap
mChangedScrap
RecyclerView的四級(jí)緩存包括:
一級(jí)緩存:mAttachedScrap和泌、mChangedScrap
二級(jí)緩存:mCacheViews
三級(jí)緩存:mViewCacheExtension
四級(jí)緩存:mRecyclerPool
一級(jí)緩存為屏幕內(nèi)緩存村缸,二級(jí)緩存為屏幕外緩存,三級(jí)緩存為自定義緩存允跑,四級(jí)緩存為緩存池緩存王凑。一二三即緩存直接不需要重新綁定View,四級(jí)緩存需要綁定Holder設(shè)置數(shù)據(jù)聋丝。禁用緩存可以使用ViewHolder的setIsRecyclable方法索烹。
參考:https://blog.csdn.net/yoonerloop/article/details/84727902
15,SurfaceView弱睦,它是什么百姓?他的繼承方式是什么?他與View的區(qū)別(從源碼角度况木,如加載垒拢,繪制等)。
SurfaceView中采用了雙緩沖機(jī)制火惊,保證了UI界面的流暢性求类,同時(shí)SurfaceView不在主線程中繪制,而是另開辟一個(gè)線程去繪制屹耐,所以它不妨礙UI線程尸疆;
SurfaceView繼承于View,他和View主要有以下三點(diǎn)區(qū)別:
(1)View底層沒有雙緩沖機(jī)制,SurfaceView有寿弱;
(2)view主要適用于主動(dòng)更新犯眠,而SurfaceView適用與被動(dòng)的更新,如頻繁的刷新
(3)view會(huì)在主線程中去更新UI症革,而SurfaceView則在子線程中刷新筐咧;
SurfaceView的內(nèi)容不在應(yīng)用窗口上,所以不能使用變換(平移噪矛、縮放量蕊、旋轉(zhuǎn)等)。也難以放在ListView或者ScrollView中摩疑,不能使用UI控件的一些特性比如View.setAlpha()
View:顯示視圖危融,內(nèi)置畫布,提供圖形繪制函數(shù)雷袋、觸屏事件、按鍵事件函數(shù)等辞居;必須在UI主線程內(nèi)更新畫面楷怒,速度較慢。
SurfaceView:基于view視圖進(jìn)行拓展的視圖類瓦灶,更適合2D游戲的開發(fā)鸠删;是view的子類,類似使用雙緩機(jī)制贼陶,在新的線程中更新畫面所以刷新界面速度比view快刃泡,Camera預(yù)覽界面使用SurfaceView。
GLSurfaceView:基于SurfaceView視圖再次進(jìn)行拓展的視圖類碉怔,專用于3D游戲開發(fā)的視圖烘贴;是SurfaceView的子類,openGL專用撮胧。
Android的構(gòu)建
1桨踪,android的構(gòu)建流程
Java的文件編譯成class 字節(jié)碼文件,然后把字節(jié)碼加依賴的第三方j(luò)ar文件一起打包成classes.dex 安卓devilk虛擬機(jī)可執(zhí)行的文件
再打包資源文件芹啥,再把dex文件和save文件合并成未簽名的包,然后簽名打包成一個(gè)完整的包
2,jenkins持續(xù)集成構(gòu)建
……待續(xù)
MVC/MVP/MVVM
1,MVC定義冀自,acitivity又充當(dāng)了View和Controller
Android 插件化
1抬驴,由來
65536/64k 方法超過限制
2,解決的問題
動(dòng)態(tài)加載APK傀履,資源加載虱朵,代碼加載
Android熱更新
1,熱更新流程
- 線上檢查到嚴(yán)重的crash
- 拉出bugfix分支并分支上修復(fù)問題
- jenkins構(gòu)建和補(bǔ)丁生成
- app通過推送或者主動(dòng)拉取補(bǔ)丁文件
- 將bugfix代碼合到主分支上
2,更新框架介紹:
Dexposed
AndFix
Nuwa
3卧秘,原理
java的加載器:PathClassLoader呢袱,DexClassLoader
機(jī)制:ClassLoader遍歷dexElements這個(gè)數(shù)組,
我們知道Java虛擬機(jī) —— JVM 是加載類的class文件的翅敌,而Android虛擬機(jī)——Dalvik/ART VM 是加載類的dex文件羞福,
而他們加載類的時(shí)候都需要ClassLoader,ClassLoader有一個(gè)子類BaseDexClassLoader,而BaseDexClassLoader下有一個(gè)
數(shù)組——DexPathList蚯涮,是用來存放dex文件治专,當(dāng)BaseDexClassLoader通過調(diào)用findClass方法時(shí),實(shí)際上就是遍歷數(shù)組遭顶,
找到相應(yīng)的dex文件张峰,找到,則直接將它return棒旗。
而熱修復(fù)的解決方法就是將新的dex添加到該集合中喘批,并且是在舊的dex的前面,所以就會(huì)優(yōu)先被取出來并且return返回铣揉。
進(jìn)程比纳睿活
1,Android進(jìn)程的優(yōu)先級(jí)
Foreground Process 前臺(tái)進(jìn)程
Visible process 可見進(jìn)程
Service process 服務(wù)進(jìn)程
Background process 后臺(tái)進(jìn)程
Empty process 空進(jìn)程
2逛拱,Android進(jìn)程的回收策略
Low memory killer:通過一些比較復(fù)雜的評(píng)分機(jī)制敌厘,對(duì)進(jìn)程進(jìn)行打分,然后將分?jǐn)?shù)高的判定為bad進(jìn)程朽合,殺死并釋放內(nèi)存俱两。
OOM _ODJ : 判別進(jìn)程的優(yōu)先級(jí)。
3曹步,進(jìn)程毕懿剩活方案
利用系統(tǒng)廣播
利用service機(jī)制拉活
利用native進(jìn)程拉活,不過后面被限制了
利用Jobscheduler機(jī)制拉活箭窜,5.0后
利用賬號(hào)同步機(jī)制拉活
a: Service設(shè)置成START_STICKY kill 后會(huì)被重啟(等待5秒左右)毯焕,重傳Intent,保持與重啟前一樣
b: 通過 startForeground將進(jìn)程設(shè)置為前臺(tái)進(jìn)程磺樱, 做前臺(tái)服務(wù)纳猫,優(yōu)先級(jí)和前臺(tái)應(yīng)用一個(gè)級(jí)別,除非在系統(tǒng)內(nèi)存非常缺竹捉,否則此進(jìn)程不會(huì)被 kill
c: 雙進(jìn)程Service: 讓2個(gè)進(jìn)程互相保護(hù)對(duì)方芜辕,其中一個(gè)Service被清理后块差,另外沒被清理的進(jìn)程可以立即重啟進(jìn)程
d: 用C編寫守護(hù)進(jìn)程(即子進(jìn)程) : Android系統(tǒng)中當(dāng)前進(jìn)程(Process)fork出來的子進(jìn)程侵续,被系統(tǒng)認(rèn)為是兩個(gè)不同的進(jìn)程倔丈。當(dāng)父進(jìn)程被殺死的時(shí)候,子進(jìn)程仍然可以存活状蜗,并不受影響(Android5.0以上的版本不可行)聯(lián)系廠商需五,加入白名單
e.鎖屏狀態(tài)下,開啟一個(gè)一像素Activity
Git
1轧坎,工作區(qū)
2宏邮,git常用命令
git init
git status
git diff
git clone
git add
git commit
3,git工作流
fork操作
Proguard
1缸血,Proguard技術(shù)點(diǎn)
壓縮(沒用到的資源和文件可以不被壓縮到包里),優(yōu)化(代碼字節(jié)碼不用的可以移除),混淆,預(yù)檢測
2蜜氨,Proguard工作原理
EntryPoint的類