1.android得啟動模式
- 標(biāo)準(zhǔn)模式(Standard)
Activity得標(biāo)準(zhǔn)模式汞窗,這種模式下每次啟動Activity都會創(chuàng)建新的Activity- 棧頂復(fù)用(singleTop)
如果打開的的Activity已經(jīng)存在棧頂酵颁,則不會重新創(chuàng)建新的Activity,而是復(fù)用棧頂?shù)腁ctivity
使用場景:短信發(fā)送界面
-棧內(nèi)復(fù)用(signleTask)
如果打開的Activity已經(jīng)在棧內(nèi)存在只恨,則不會重新創(chuàng)建新的Activity,二手復(fù)棧內(nèi)的Activity,將改Activity以上的Activity銷毀掉
使用場景:瀏覽器的Activity- 全局唯一模式(singleInstance)
整個手機(jī)操作系統(tǒng)只有一個實(shí)例寸谜,并且運(yùn)行子啊單獨(dú)的任務(wù)棧中
使用場景:撥號界面的Activity
2.Activity A-B的生命周期
- 問題描述:打開(A)Activity并打開(B)Activity瘤运。請描述整個生命周期?
onCreate:表示創(chuàng)建犁嗅,這個是生命周期的第一個方法。此時Activity還是處于后臺晤碘,不可見褂微。
onStart:表示啟動功蜓,這個是生命周期的第二個方法。此時Activity處于可見宠蚂,但是還是沒有出現(xiàn)在前臺
onResume:表示繼續(xù)式撼、重新開始,這個階段表示Activity處于前臺并且是可見的狀態(tài)
onPause:表示暫停求厕。這個階段處于可見并在在前臺著隆。在這個階段可以存儲數(shù)據(jù)操作。但是不能進(jìn)行耗時操作呀癣。
onStop;表示暫停美浦。此時Activity處于不可見狀態(tài),但是資源還在內(nèi)存中
onDestory:表示銷毀项栏。此時Activity處于不可見狀態(tài)浦辨,并且資源也被回收了。
onRestart:表示重新開始沼沈。Acticity處于可見狀態(tài)荤牍。
- 生命周期執(zhí)行過程
(A)OnCreate->(A)OnStart->(A)OnResume->(A)OnPause->(B)OnCreate->(B)OnStart->(B)OnResume->(A)OnStop
- 為什么(A)Onstop在最后執(zhí)行
因?yàn)樵谶@個跳轉(zhuǎn)過程中會出現(xiàn)立刻返回界面,為了快速恢復(fù)庆冕。因此在(B)Activity處于可見前臺的時候再執(zhí)行Onstop
3.切換Fragment的replace方法里面做了什么?
fragment本身沒有replace和add方法劈榨;這里泛指的是fragmentManager中的replace和add的方法访递;在fragment的容器中有個framelayout;add的時候?qū)⒚恳粋€fragment疊加到framelayout上面去,顯示隱藏則通過show方法或hind方法同辣,生命周期只有再add的會重新執(zhí)行拷姿,后續(xù)不會再執(zhí)行生命周期,而replace的時候?qū)⑵渌鹒ragment去除掉旱函,然后再添加fragment到framelayout上去响巢。每一次replace都會執(zhí)行一次生命周期。
4.Toast能不能在子線程中彈出棒妨,算不算Ui更新踪古?
Toast屬于window層的邏輯,與activity并級券腔。所謂的ui更新指的是刷新activity的跟布局伏穆。因此不算UI更新
5.Handler相關(guān)
- 消息機(jī)制模型
Handler:接受和發(fā)送Message
Message:消息承載體
MessageQueue:以鏈表結(jié)構(gòu),通過enQueueMessage插入Message
Looper:將Handler與MessageQueue關(guān)聯(lián)起來(1.Handler獲取主線程的MessageQueue纷纫;2.主線程從MessageQueue中獲取Message并回調(diào)到Handler)
- 消息機(jī)制的運(yùn)行流程
在子線程執(zhí)行完耗時操作枕扫,當(dāng)Handler發(fā)送消息時,將會調(diào)用MessageQueue.enqueueMessage辱魁,向消息隊(duì)列中添加消息烟瞧。當(dāng)通過Looper.loop開啟循環(huán)后诗鸭,會不斷從線程池中讀取消息,即調(diào)用MessageQueue.next,然后調(diào)用目標(biāo)Handler的dispatchMessage方法傳遞消息参滴,然后返回到Handler所在的線程强岸,目標(biāo)Handler收到消息,調(diào)用handlerMessage方法卵洗,接受消息请唱,處理消息。
- MessageQueue过蹂、Handler和Looper三者關(guān)系
每一個線程只能存在一個Looper,Looper是保存在ThreadLocal中十绑,主線程已經(jīng)創(chuàng)建了一個Looper,所以在主線程中不需要再創(chuàng)建Looper酷勺,但是再其他線程中需要創(chuàng)建Looper本橙,每個線程可以有多個Handler,既一個Looper可以處理來自多個Handler的消息脆诉,Looper中維護(hù)一個MessageQueue甚亭,來維護(hù)消息隊(duì)列,消息隊(duì)列中的Message可以來自不同的Handler击胜。
- 線程遍歷數(shù)據(jù)
MessageQueue調(diào)用EnqueueMessage將Message插入到鏈表中去亏狰,由于外部隨時隨地向MessageQueue中發(fā)送消息,因此MessageQueue調(diào)用next方法開啟循環(huán)來反復(fù)取鏈表頭部消息偶摔。如果消息時間戳小于或等于當(dāng)前時間戳則返回隊(duì)頭消息暇唾,反之取消息時間戳和當(dāng)前時間戳差值,并調(diào)用navtaPollOnce方法延長一段時間后 再次循環(huán)辰斋。
- 線程切換
將子線程持有的Handler與主線程關(guān)聯(lián)的mainMessageQueue綁定在一起策州,主線程負(fù)責(zé)循環(huán)從mainMessageQueue中取出消息,然后調(diào)用Handler中的dispatchMessage方法切換線程宫仗。- Looper關(guān)聯(lián)Handler與MessageQueue
主線程通過prepareMainLooper以此來完成對sMainLooper的初始化,調(diào)用loop方法循環(huán)取值并進(jìn)行處理够挂,如果沒有消息則暫停。子線程拿到sMainLoop后就此初始化Handler,這樣子線程發(fā)送到Handler的消息就存儲再mainMessageQueue中
- MessageQueue的創(chuàng)建
nativeInit會創(chuàng)建一個native層的MessageQueue,并將引用地址返回給java層的mPtr變量中藕夫。- 消息屏障
PostSyncBarrier,插入一個無target的message孽糖,這個屏障之后的所有同步消息都不會執(zhí)行- NaticePollOnce
通過native層的MessageQueue阻塞nextPollTimeOutMillis毫秒的時間,調(diào)用native層的MessageQueue的Looper的epoll_wait毅贮,是linux下多路復(fù)用IO接口的增強(qiáng)版本梭姓。- MessageQueue入隊(duì)列時會喚醒等到線程nativeWakeup,write,寫入了一個1,這個時候epoll就能監(jiān)聽到事件嫩码,也就唄喚醒了誉尖。
- Handler的post(Runnable)是怎么實(shí)現(xiàn)的
post()調(diào)用Handler的SendMessageDelayed()方法,根據(jù)參數(shù)Runnable創(chuàng)建一個Message對象铸题,發(fā)送一個延遲未0 的延遲消息铡恕,最終調(diào)用到Handler的EnqueMessage方法將消息按照事件先后順序添加到MessageQueue中琢感,然后通過Looper的loop方法不斷的從MessageQueue中取消息分發(fā)給Handler處理
- Looper.loop()里面是死循環(huán),為什么不會卡死
Android系統(tǒng)是消息驅(qū)動的,Handler發(fā)送的消息保存在MessageQueue中探熔,只有l(wèi)ooper.loop在不斷循環(huán)取消息驹针,才能讓系統(tǒng)繼續(xù)進(jìn)行,主線程也是一個線程诀艰,不然一旦主線程中的代碼執(zhí)行完成柬甥,主線程就會結(jié)束,那么整個應(yīng)用也就結(jié)束了其垄,只有讓主線程不結(jié)束那么應(yīng)用就會一直運(yùn)行苛蒲,
Activity的生命周期都說通過Handler發(fā)送消息,然后ActivityThread的內(nèi)部類H接受消息绿满,并回調(diào)相關(guān)的生命周期函數(shù)臂外,如果沒有死循環(huán),就無法不斷的從MessageQueue中取消息喇颁,也就無法回調(diào)各種生命周期函數(shù)了
- Loop.prepare做了什么
判斷了當(dāng)前線程是否以及創(chuàng)建了一個Loop漏健,如果以及有了Looper就拋出異常,否則就創(chuàng)建一個新的Looper保存到ThreadLocal中
- MessageQueue是什么時候創(chuàng)建的
在Loop.preare中線判斷了Looper是否創(chuàng)建橘霎,沒有創(chuàng)建則先創(chuàng)建一個Looper蔫浆,在Looper的構(gòu)造函數(shù)中創(chuàng)建一個MessageQueue。
- handler.sendEmptyMessageDelay和handler.postDelayed的區(qū)別
兩者都會調(diào)用handler.sendMessageDelayed,sendEmptyDelayed內(nèi)部會根據(jù)what創(chuàng)建一個新的Message,postDelayed根據(jù)參數(shù)Runnable創(chuàng)建一個帶有callBack的Message,在分發(fā)的時候優(yōu)先給了handleCallback姐叁,事件處理是在傳入?yún)?shù)的Runnaable的run方法中瓦盛,而sendEmptyDelayed最終事件處理在Handler的handlerMessage中
6.Android中的Context、Activity七蜘、Application有什么區(qū)別
- Context
1.描述的是一個應(yīng)用程序的環(huán)境信息,即上下文
2.該類是一個抽象類
3.通過他我們可以獲取應(yīng)用程序的資源墙懂、類或者其他的例如啟動Activity橡卤、發(fā)送廣播。接受Intent
4.一個Context等于Activity+service+1
- 相同點(diǎn)
Activity和Application都是Context的子類
- 不同點(diǎn)
三者維護(hù)的生命周期不同
Application:維護(hù)的是整個項(xiàng)目的生命周期
Context和Activity:維護(hù)的是當(dāng)前Activity的生命周期
7.事件分發(fā)機(jī)制
- View的事件分發(fā)機(jī)制
事件分發(fā)的本質(zhì):就是對MotionEvent事件分發(fā)的過程损搬,即當(dāng)一個MotionEvent產(chǎn)生了以后碧库,系統(tǒng)需要將這個事件傳遞到一個具體的View上,點(diǎn)擊事件的傳遞順序:硬件----Activity------ViewGroup-----View
- Activity分發(fā)
1.事件先分發(fā)給PhoneWindow巧勤、PhoneWindow不消費(fèi)則傳遞給Activity的OnTouchEvenet方法嵌灰。
2.PhoneWindow傳給DecorView,DecorView傳給根布局ViewGroup- ViewGroup分發(fā)
1.首先調(diào)用OnInterCeptTouchEvent方法,判斷ViewGroup自己是否需要颅悉,需要則攔截沽瞭,攔截后就不會傳遞給ChildView。
2.攔截后剩瓶,調(diào)用VieGroup自己的OntouchEvent方法
3.不攔截則傳遞給childView驹溃,按照視圖層次結(jié)構(gòu)依次傳遞下去城丧。
4.最終的那個childView也不需要時,事件會進(jìn)行回傳豌鹤,以此調(diào)用前面每一層的OnTouchEvent方法亡哄。- View分發(fā)
1.View會依次調(diào)用onTouchListener、onTouchEvent布疙、OnLongClickListener蚊惯、OnclickListener。
2.在OnTouchListener灵临、OntouchEvent中可以決定是否消費(fèi)事件截型、不消費(fèi)事件則開始回傳
3.注冊了OnLongClickListener、OnClickListener及設(shè)置了Clickable等俱诸,View就會消費(fèi)事件
8.Window菠劝、Activity、Decorview以及ViewRoot之間的關(guān)系
Activity:一個控制器統(tǒng)籌視圖的添加和顯示睁搭,以及通過其他方法來與Window赶诊、以及View進(jìn)行交互
Window:視圖的承載器,內(nèi)部持有一個DecorView,而這個Decorview才是View的根布局园骆,實(shí)際再ACtivity中持有的是其子類PhoneWindow舔痪。PhoneWindow中有個內(nèi)部類DecorView,通過DecorView來加載Activity中設(shè)置的布局文件。Window通過WindowManager將Decorview加載其中锌唾,并將Decorview交給ViewRoot锄码,進(jìn)行視圖繪制以及其他交互。
Decorview:Decorview是FrameLayout的子類晌涕,他被認(rèn)為是Android視圖樹的根節(jié)點(diǎn)視圖滋捶,Decorview作為頂級View,一般情況下他內(nèi)部包含一個豎直方向的linearLayout余黎,再這個LinearLayout里面有上中下三部分組成
ViewRoot:負(fù)責(zé)View的事件處理和邏輯處理
9.ARouter相關(guān)
- ARouter路由原理
ARouter維護(hù)了一個路由表Warehouse重窟,其中保存著全部的模塊跳轉(zhuǎn)關(guān)系,ARouter路由跳轉(zhuǎn)實(shí)際上還是調(diào)用了startActivity的跳轉(zhuǎn)惧财,使用了原生的Framework機(jī)制巡扇,只是通過apt注解的形式制造出跳轉(zhuǎn)規(guī)則,并人為地攔截跳轉(zhuǎn)和設(shè)置跳轉(zhuǎn)條件
- ARouter初始化做了什么
在ARouter的init方法中調(diào)用了_ARouter的init方法垮衷,在初始化過后接著調(diào)用了_ARouter的afterInit方法做后續(xù)的工作厅翔。
在_ARouter的init中調(diào)用了LogisiticsCenter.init,并初始化了一個主線程的Handler搀突。在該方法中調(diào)用ClassUtils.getFileNameByPackageName方法在子線程中掃描出第二個參數(shù)開頭的類添加到Set集合中調(diào)用對應(yīng)接口的loadInto方法刀闷,這些接口的loadInto方法具體實(shí)現(xiàn)在編輯器自動生成的類中,在這些自動生成的類中,將對應(yīng)的路由信息添加到Warehose類的靜態(tài)Map中涩赢。
- ARouter是怎么啟動Activity或者Fragment的
在編譯期戈次,注解處理器會獲取到@ARouter注解中的類相關(guān)信息Element,然后遍歷所有的Element,檢查注解使用的合法性筒扒,然后用javaPoet生成相關(guān)的路由類怯邪,這些類保存這跳轉(zhuǎn)相關(guān)信息,這些信息根據(jù)模塊名分組花墩,每個模塊中加上@ARouter注解的類被添加到對應(yīng)的組中悬秉,每個組中保存者改類的路由信息,
在運(yùn)行期冰蘑,ARouter初始化的時候遍歷dex文件中所有的類過濾出包名以com.alibaba.android.arouter.routes開頭的類添加到Set集合中和泌,然后遍歷該Set集合,然后調(diào)用對應(yīng)類的loadInto方法祠肥,將路由信息添加到Warehouse類中的靜態(tài)Map中武氓,在路由跳轉(zhuǎn)的時候,build方法根據(jù)傳入的path提取出group仇箱,并封裝成postCard對象县恕,navigation方法中,從靜態(tài)Map中根據(jù)之前封裝到PostCard中的path查詢出RouteMeta,然后將要跳轉(zhuǎn)的類信息設(shè)置給PostCard對此剂桥,最終調(diào)用到了_ARouter類的_navigation方法忠烛,在該方法中根據(jù)postCard對象中的信息用Intent進(jìn)行跳轉(zhuǎn)
11.Retrofit實(shí)現(xiàn)原理
retrofit基于okHttp封裝成RESTFUL網(wǎng)絡(luò)請求框架,通過工廠模式配置各種參數(shù)权逗,通過動態(tài)代理美尸、注解實(shí)現(xiàn)網(wǎng)絡(luò)請求。retrofit利用了工廠模式斟薇,將分為生產(chǎn)網(wǎng)絡(luò)請求執(zhí)行器(callFactory)师坎、回調(diào)方法執(zhí)行器(callbackExecutor)、網(wǎng)絡(luò)請求適配器(CallAdapterFactory)堪滨、數(shù)據(jù)轉(zhuǎn)換器(converterFactory)等幾種工廠胯陋。
callFactory負(fù)責(zé)生產(chǎn)okHttp的call,大家都知道okHttp通過生成call對象完成同步和異步的http請求椿猎。
callbackExecutor通過判斷不同的平臺惶岭,生成對應(yīng)平臺的數(shù)據(jù)回調(diào)執(zhí)行器寿弱。其中android端的回調(diào)執(zhí)行器是通過handler回調(diào)數(shù)據(jù)犯眠。
CallAdapterFactory是數(shù)據(jù)解析工廠,一般我們配置json的數(shù)據(jù)解析適配器就行症革。
converterFactory是數(shù)據(jù)轉(zhuǎn)換的工廠筐咧,一般我們配置Rxjava的數(shù)據(jù)轉(zhuǎn)換就行。
retrofit通過動態(tài)代理模式實(shí)現(xiàn)接口類配置的注解、參數(shù)解析成HTTP對象量蕊,最后通過okHttp實(shí)現(xiàn)網(wǎng)絡(luò)請求铺罢。
- retrofit動態(tài)代理
1.首先,通過method把它轉(zhuǎn)換成ServiceMethod残炮。
2.然后韭赘,通過serviceMethod,args獲取到okHttpCall對象势就。
3.最后泉瞻,再把okHttpCall進(jìn)一步封裝并返回Call對象。
12.Appliction啟動過程(App啟動過程)
應(yīng)用啟動涉及四個進(jìn)程:調(diào)用者進(jìn)程(點(diǎn)擊桌面圖標(biāo)啟動苞冯,那么就是Launcher進(jìn)程)袖牙、SystemServer進(jìn)程(AMS管理Activity的啟動)、Zygote進(jìn)程(fork子進(jìn)程:共享代碼空間舅锄、數(shù)據(jù)空間獨(dú)立)鞭达、新的應(yīng)用進(jìn)程。
整體流程是:點(diǎn)擊桌面圖標(biāo)啟動時皇忿,啟動請求通過Binder方式發(fā)送給SystemServer中的ActivityManagerService畴蹭,AMS接收到啟動請求后檢查應(yīng)用進(jìn)程是否存在,如果不存在則通過Zygote進(jìn)程fork子進(jìn)程禁添,之后回到AMS進(jìn)程處理處理Intent撮胧、Flag信息,創(chuàng)建任務(wù)棧老翘、Activity進(jìn)棧芹啥,之后轉(zhuǎn)到新進(jìn)程,創(chuàng)建ActivityThread對象铺峭,調(diào)用其main方法墓怀,main方法所在的就是主線程,其中還會創(chuàng)建Looper綁定主線程卫键,之后調(diào)用loop()方法開啟消息循環(huán)
13.Okhttp原理
- 原理
okhttp主要實(shí)現(xiàn)了異步傀履、同步的網(wǎng)絡(luò)操作,創(chuàng)建了不同的call對象莉炉,這里的call對象是一個個的runnable對象钓账,由于我們的任務(wù)是很多的,因此這里有Dispatcher包裝了線程池來處理不同的call絮宁,其中該類中創(chuàng)建了三種隊(duì)列梆暮,分別用于存放正在執(zhí)行的異步任務(wù),同步隊(duì)列绍昂,以及準(zhǔn)備的隊(duì)列啦粹。最后在執(zhí)行每個任務(wù)的時候偿荷,采用隊(duì)列的先進(jìn)先出原則,處理每一個任務(wù)唠椭,都是交給了后面的各種攔截器來處理跳纳,有請求準(zhǔn)備的攔截器、緩存攔截器贪嫂、網(wǎng)絡(luò)連接的攔截器寺庄,每一個攔截器組成了一個責(zé)任鏈的形式。到最后返回response信息力崇。
OkHttp的底層是通過Java的Socket發(fā)送HTTP請求與接受響應(yīng)的(這也好理解铣揉,HTTP就是基于TCP協(xié)議的),但是OkHttp實(shí)現(xiàn)了連接池的概念餐曹,即對于同一主機(jī)的多個請求逛拱,其實(shí)可以公用一個Socket連接,而不是每次發(fā)送完HTTP請求就關(guān)閉底層的Socket台猴,這樣就實(shí)現(xiàn)了連接池的概念朽合。而OkHttp對Socket的讀寫操作使用的OkIo庫進(jìn)行了一層封裝
14.RxJava 的線程切換原理
- RxJava通過subscribeOn指定被觀察者發(fā)生的線程,observeOn指定觀察者發(fā)生的線程饱狂。其中Schedulers.IO生成的是IoScheduler曹步。通過觀察者與被觀察者訂閱的過程中,首先會觸發(fā)被觀察者的subscribeActual方法休讳,在該方法中讲婚,可以看到最終會走scheduler的schedule方法,所以上面提到的IoScheduler實(shí)際是調(diào)用了它的schedule方法俊柔,最終會在NewThreadWorker里面生成ScheduledExecutorService對象筹麸,而ScheduledExecutorService實(shí)際是由ScheduledThreadPoolExecutor創(chuàng)建的一個核心線程,最大線程個數(shù)是Integer.MAX_VALUE的線程池雏婶。最終會由ScheduledThreadPoolExecutor的submit或schedule方法執(zhí)行傳過來的Runnable對象物赶,而Runnable執(zhí)行的是被觀察者的subscribe方法。所以解釋了被觀察者的subscribe方法是在子線程中執(zhí)行的留晚。
- observeOn是觀察者發(fā)生的線程酵紫,AndroidSchedulers.mainThread()實(shí)質(zhì)是HandlerScheduler對象,而在觀察者部分错维,最終觀察部分會走Scheduler的scheduleDirect方法奖地,而HandlerScheduler的該方法里面包裝了一個ScheduledRunnable對象,通過主線程的handler.postDelayed處理這個runnable對象
15.RecyclerView源碼赋焕、緩存分析
RecyclerView使用了強(qiáng)大的分工操作参歹,顯示、排版由LayoutManager處理宏邮,數(shù)據(jù)顯示由adapter處理泽示,item上下左右動態(tài)加入繪制由ItemDecoration處理,item的動畫由ItemAnimator處理蜜氨。面試主要分析recyclerView緩存械筛,recyclerView緩存是由內(nèi)部類Recycler維護(hù),其中一級緩存有mAttachedScrap飒炎,里面放的都是當(dāng)前屏幕正在顯示的viewHolder的緩存埋哟,二級緩存是mCachedViews,里面放的都是移出到屏幕外的viewHolder緩存郎汪,mRecyclerPool是recyclerView的三級緩存赤赊,一般用在RecyclerView嵌套RecyclerView的時候用得到,比如外層的RecyclerView的item中有RecyclerView煞赢,那么里面的RecyclerView通過共用外層的RecyclerView的RecyclerPool來減少里面RecyclerView的ViewHolder創(chuàng)建
16.Jetpack
android jetpack是google專門為開發(fā)者快速開發(fā)app的一套組件抛计,快速搭建mvvm框架的實(shí)現(xiàn),其中包括Lifecyle照筑、LiveData吹截、ViewModel、Room凝危、DadaBinding波俄、Navigation、Paging蛾默、WorkManager等一系列優(yōu)秀的框架
- Lifecycle
實(shí)現(xiàn)和activity懦铺、fragment生命周期感知的框架,實(shí)現(xiàn)數(shù)據(jù)層和view層銷毀的時候解綁支鸡。原理是Lifecycler為每個活動組件添加了一個沒有界面的Fragment冬念,利用Fragment周期會根據(jù)活動聲明周期變化的特性實(shí)現(xiàn)的特性,從而實(shí)現(xiàn)生命周期的感知牧挣,然后根據(jù)注解的Event查找執(zhí)行相應(yīng)的方法
- LiveData
提供了一種數(shù)據(jù)改變的同時刘急,主動去告訴ui,讓ui層做出相應(yīng)的邏輯判斷浸踩。原理是內(nèi)部保存了LifecycleOwner和Observer叔汁,利用LifecycleOwner感知并處理聲明中期的變化,Observer在數(shù)據(jù)改變時遍歷所有觀察者并回調(diào)方法
- ViewModel
它是我們view層和model層的橋梁检碗,是數(shù)據(jù)驅(qū)動界面的關(guān)鍵地方据块,也是我們ui層在數(shù)據(jù)丟失的情況下,viewModel還能繼續(xù)保持原有的數(shù)據(jù)折剃,原理是將數(shù)據(jù)保存到ViewModel中另假,然后為活動中添加一個HolderFragment,HolderFragment中保存了ViewStore的實(shí)例怕犁,ViewStore中使用Map保存了ViewModel边篮,從而在活動重新創(chuàng)建時獲取到原來的ViewModel己莺。
- Room
是model層本地數(shù)據(jù)庫的框架,通過實(shí)體映射到對應(yīng)的db表結(jié)構(gòu)戈轿,將實(shí)體映射到db關(guān)系型數(shù)據(jù)庫里面凌受。跟greendao差不多,room數(shù)據(jù)庫版本升級數(shù)據(jù)遷移比greendao遷移要麻煩思杯,個人還是比較喜歡greendao來實(shí)現(xiàn)本地數(shù)據(jù)庫胜蛉。 DadaBinding:是一個可以通過在xml布局文件中實(shí)現(xiàn)ui邏輯的框架,并且它的ui層和數(shù)據(jù)層雙向驅(qū)動還是挺不錯的色乾。
- Navigation
是后面新出來的可視化管理fragment的組件誊册,通過在xml中配置fragment之間跳轉(zhuǎn)的關(guān)系。
17.Eventbus原理
EventBus是一款在android開發(fā)中使用的發(fā)布/訂閱事件的總線框架暖璧,基于觀察者模式案怯,將事件的接收者和發(fā)送者分開,基本包括了如下幾個步驟:
注冊事件的訂閱方法:該步驟主要是找到訂閱者下面有哪些方法需要被訂閱
訂閱操作:將需要被訂閱的方法放到類似HashMap的數(shù)據(jù)結(jié)構(gòu)中存儲起來澎办,方便后面發(fā)送事件和取消注冊等資源的釋放的時候使用
發(fā)送事件:該步驟首先遍歷事件隊(duì)列殴泰,然后從隊(duì)列中取出事件,并且將事件從隊(duì)列中移除浮驳,拿到事件后悍汛,判斷事件處于的什么線程,如果是非UI線程至会,則需要Handler去處理离咐,如果是的話,則直接通過反射調(diào)用被觀察的方法奉件。
反注冊:該步驟就沒什么好說的宵蛀,主要是上面存儲到HashMap中的被訂閱的方法的移除,釋放在內(nèi)存中的資源县貌。
18.View的繪制原理
View的繪制從ActivityThread類中Handler的處理RESUME_ACTIVITY事件開始犬辰,在執(zhí)行performResumeActivity之后野芒,創(chuàng)建Window以及DecorView并調(diào)用WindowManager的addView方法添加到屏幕上,addView又調(diào)用ViewRootImpl的setView方法,最終執(zhí)行performTraversals方法典鸡,依次執(zhí)行performMeasure边翁,performLayout洒放,performDraw顾画。也就是view繪制的三大過程。
measure過程測量view的視圖大小巷帝,最終需要調(diào)用setMeasuredDimension方法設(shè)置測量的結(jié)果忌卤,如果是ViewGroup需要調(diào)用measureChildren或者measureChild方法進(jìn)而計算自己的大小。
layout過程是擺放view的過程楞泼,View不需要實(shí)現(xiàn)驰徊,通常由ViewGroup實(shí)現(xiàn)笤闯,在實(shí)現(xiàn)onLayout時可以通過getMeasuredWidth等方法獲取measure過程測量的結(jié)果進(jìn)行擺放。
draw過程先是繪制背景棍厂,其次調(diào)用onDraw()方法繪制view的內(nèi)容颗味,再然后調(diào)用dispatchDraw()調(diào)用子view的draw方法,最后繪制滾動條勋桶。ViewGroup默認(rèn)不會執(zhí)行onDraw方法,如果復(fù)寫了onDraw(Canvas)方法侥猬,需要調(diào)用 setWillNotDraw(false);清楚不需要繪制的標(biāo)記例驹。
requestLayout,invalidate退唠,postInvalidate
相同點(diǎn):三個方法都有刷新界面的效果鹃锈。
不同點(diǎn):invalidate和postInvalidate只會調(diào)用onDraw()方法;requestLayout則會重新調(diào)用onMeasure瞧预、onLayout屎债、onDraw。
調(diào)用了invalidate方法后垢油,會為該View添加一個標(biāo)記位盆驹,同時不斷向父容器請求刷新,父容器通過計算得出自身需要重繪的區(qū)域滩愁,直到傳遞到ViewRootImpl中躯喇,最終觸發(fā)performTraversals方法,進(jìn)行開始View樹重繪流程(只繪制需要重繪的視圖)硝枉。
調(diào)用requestLayout方法廉丽,會標(biāo)記當(dāng)前View及父容器,同時逐層向上提交妻味,直到ViewRootImpl處理該事件正压,ViewRootImpl會調(diào)用三大流程,從measure開始责球,對于每一個含有標(biāo)記位的view及其子View都會進(jìn)行測量onMeasure焦履、布局onLayout、繪制onDraw雏逾。
19.RecyclerView與ListView(緩存原理裁良,區(qū)別聯(lián)系,優(yōu)缺點(diǎn))
緩存區(qū)別:
層級不同:
ListView有兩級緩存校套,在屏幕與非屏幕內(nèi)价脾。
RecyclerView比ListView多兩級緩存,支持多個離屏ItemView緩存(匹配pos獲取目標(biāo)位置的緩存笛匙,如果匹配則無需再次bindView)侨把,支持開發(fā)者自定義緩存處理邏輯犀变,支持所有RecyclerView共用同一個RecyclerViewPool(緩存池)。
緩存不同:
ListView緩存View秋柄。
RecyclerView緩存RecyclerView.ViewHolder获枝,抽象可理解為:
View + ViewHolder(避免每次createView時調(diào)用findViewById) + flag(標(biāo)識狀態(tài));
優(yōu)點(diǎn)
RecylerView提供了局部刷新的接口骇笔,通過局部刷新省店,就能避免調(diào)用許多無用的bindView。
RecyclerView的擴(kuò)展性更強(qiáng)大(LayoutManager笨触、ItemDecoration等)懦傍。
20. Activity的啟動過程
app啟動的過程有兩種情況,第一種是從桌面launcher上點(diǎn)擊相應(yīng)的應(yīng)用圖標(biāo)芦劣,第二種是在activity中通過調(diào)用startActivity來啟動一個新的activity粗俱。
我們創(chuàng)建一個新的項(xiàng)目,默認(rèn)的根activity都是MainActivity虚吟,而所有的activity都是保存在堆棧中的寸认,我們啟動一個新的activity就會放在上一個activity上面,而我們從桌面點(diǎn)擊應(yīng)用圖標(biāo)的時候串慰,由于launcher本身也是一個應(yīng)用偏塞,當(dāng)我們點(diǎn)擊圖標(biāo)的時候,系統(tǒng)就會調(diào)用startActivitySately(),一般情況下邦鲫,我們所啟動的activity的相關(guān)信息都會保存在intent中烛愧,比如action,category等等掂碱。我們在安裝這個應(yīng)用的時候怜姿,系統(tǒng)也會啟動一個PackaManagerService的管理服務(wù),這個管理服務(wù)會對AndroidManifest.xml文件進(jìn)行解析疼燥,從而得到應(yīng)用程序中的相關(guān)信息沧卢,比如service,activity醉者,Broadcast等等但狭,然后獲得相關(guān)組件的信息。當(dāng)我們點(diǎn)擊應(yīng)用圖標(biāo)的時候撬即,就會調(diào)用startActivitySately()方法立磁,而這個方法內(nèi)部則是調(diào)用startActivty(),而startActivity()方法最終還是會調(diào)用startActivityForResult()這個方法。而在startActivityForResult()這個方法剥槐。因?yàn)閟tartActivityForResult()方法是有返回結(jié)果的唱歧,所以系統(tǒng)就直接給一個-1,就表示不需要結(jié)果返回了。而startActivityForResult()這個方法實(shí)際是通過Instrumentation類中的execStartActivity()方法來啟動activity颅崩,Instrumentation這個類主要作用就是監(jiān)控程序和系統(tǒng)之間的交互几于。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理對象,通過這個代理對象進(jìn)行啟動activity沿后。啟動會就會調(diào)用一個checkStartActivityResult()方法沿彭,如果說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了尖滚。當(dāng)然最后是調(diào)用的是Application.scheduleLaunchActivity()進(jìn)行啟動activity喉刘,而這個方法中通過獲取得到一個ActivityClientRecord對象,而這個ActivityClientRecord通過handler來進(jìn)行消息的發(fā)送漆弄,系統(tǒng)內(nèi)部會將每一個activity組件使用ActivityClientRecord對象來進(jìn)行描述睦裳,而ActivityClientRecord對象中保存有一個LoaderApk對象,通過這個對象調(diào)用handleLaunchActivity來啟動activity組件置逻,而頁面的生命周期方法也就是在這個方法中進(jìn)行調(diào)用推沸。备绽。