activity的幾種啓動模式是android中常考的知識點,通常會考察有哪幾種啓動模式,以及每種啓動模式在什麼場景下使用:java
standard
:這個是android默認的Activity啓動模式,每啓動一個Activity都會被實例化一個Activity,而且新建立的Activity在堆棧中會在棧頂。android
singleTop
:若是當前要啓動的Activity就是在棧頂的位置,那麼此時就會複用該Activity,而且不會重走onCreate方法,會直接它的onNewIntent
方法,若是不在棧頂,就跟standard
同樣的。若是當前activity已經在前臺顯示着,忽然來了一條推送消息,此時不想讓接收推送的消息的activity再次建立,那麼此時正好能夠用該啓動模式,若是以前activity棧中是A-->B-->C若是點擊了推進的消息仍是A-->B--C,不過此時C是不會再次建立的,而是調用C的onNewIntent。而若是如今activity中棧是A-->C-->B,再次打開推送的消息,此時跟正常的啓動C就沒啥區別了,當前棧中就是A-->C-->B-->C了。面試
singleTask
:該種狀況下就比singleTop
厲害了,無論在不在棧頂,在Activity的堆棧中永遠保持一個。這種啓動模式相對於singleTop而言是更加直接,好比以前activity棧中有A-->B-->C---D,再次打開了B的時候,在B上面的activity都會從activity棧中被移除。下面的acitivity仍是不用管,因此此時棧中是A-->B,通常項目中主頁面用到該啓動模式。數據庫
singleInstance
:該種狀況就用得比較少了,主要是指在該activity永遠只在一個單獨的棧中。一旦該模式的activity的實例已經存在於某個棧中,任何應用在激活該activity時都會重用該棧中的實例,解決了多個task共享一個activity。其他的基本和上面的singleTask保持一致。json
上面的各類啓動模式主要是經過配置清單文件,常見還有在代碼中設置flag也能實現上面的功能:數組
FLAG_ACTIVITY_CLEAR_TOP
:這種啓動的話,只能單純地清空棧上面的acivity,而本身會從新被建立一次,若是當前棧中有A-->B-->C這幾種狀況,從新打開B以後,此時棧會變成了A-->B,可是此時B會被從新建立,不會走B的onNewIntent方法。這就是單獨使用FLAG_ACTIVITY_CLEAR_TOP
的用處,能清空棧上面的activity,可是本身會從新建立。 若是在上面的基礎上再加上FLAG_ACTIVITY_SINGLE_TOP
此時就不從新建立B了,也就直接走B的onNewIntent。它二者結合着使用就至關於上面的singleTask模式。 若是隻是單獨的使用FLAG_ACTIVITY_SINGLE_TOP
跟上面的singleTop就沒啥區別了。緩存
FLAG_ACTIVITY_CLEAR_TOP+FLAG_ACTIVITY_SINGLE_TOP=singleTask
,此時要打開的activity不會被重建,只是走onNewIntent方法。性能優化
FLAG_ACTIVITY_SINGLE_TOP=singleTop
bash
FLAG_ACTIVITY_NEW_TASK
服務器
在相同taskAffinity狀況下:啓動activity是沒有任何做用的。
在不一樣taskAffinity狀況下: 若是啓動不一樣棧中的activity已經存在了某一個棧中的activity,那麼此時是啓動不了該activity的,由於棧中已經存在了該activity;若是棧中不存在該要啓動的activity,那麼會啓動該acvitity,而且將該activity放入該棧中。
FLAG_ACTIVITY_NEW_TASK
和FLAG_ACTIVITY_CLEAR_TOP
一塊兒使用,而且要啓動的activity的taskAffinity和當前activity的taskAffinity不同纔會和singleTask同樣的效果,由於要啓動的activity和原先的activity不在同一個taskAffinity中,因此能啓動該activity,這個地方有點繞,寫個簡單的公式:
FLAG_ACTIVITY_NEW_TASK
若是啓動同一個不一樣taskAffinity的activity纔會有效果。FLAG_ACTIVITY_NEW_TASK
和FLAG_ACTIVITY_CLEAR_TOP
若是一塊兒使用要開啓的activity和如今的activity處於同一個taskAffinity,那麼效果仍是跟沒加FLAG_ACTIVITY_NEW_TASK
是同樣的效果。FLAG_ACTIVITY_NEW_TASK
和FLAG_ACTIVITY_CLEAR_TOP
啓動和如今的activity不是同一個taskAffinity纔會和singleTask同樣的效果。FLAG_ACTIVITY_CLEAR_TASK
FLAG_ACTIVITY_NEW_TASK
一塊兒使用,啓動activity是沒有任何做用的。FLAG_ACTIVITY_NEW_TASK
一塊兒使用,若是要啓動的activity不存在棧中,那麼啓動該acitivity,而且將該activity放入該棧中,若是該activity已經存在於該棧中,那麼會把當前棧中的activity先移除掉,而後再將該activity放入新的棧中。FLAG_ACTIVITY_NEW_TASK
+FLAG_ACTIVITY_SINGLE_TOP
用在當app正在運行點擊push消息進到某個activity中的時候,若是當前處於該activity,此時會觸發activity的onNewIntent。
FLAG_ACTIVITY_NEW_TASK
+FLAG_ACTIVITY_CLEAR_TOP
用在app沒在運行中,啓動主頁的activity,而後在相應的activity中作相應的activity跳轉。
消息機制指Handler、Looper、MessageQueue、Message之間如何工做的。
handler是用來處理消息和接收消息的中間者,handler的建立會伴隨着handler中產生looper和MessageQueue,handler依賴於looper,looper依賴於MessageQueue,因此在子線程中使用handler拋出異常是由於子線程中沒有初始化looper對象,而主線程中looper是在ActivityThread
中已經初始化過了,因此能直接在主線程中能拿到Handler。
Looper是用來輪詢消息,說白了就是經過loop方法實現死循環,有消息的時候,經過MessageQueue.next方法取出message,沒有消息的時候,線程處於阻塞的狀態。在有消息的時候獲取到消息,將消息交給了handler,handler會根據消息中有沒有callback,若是有callback會直接callback,不然經過handleMessage處理。
MessageQueue是一個單鏈表結構來存儲Message,每次經過next方法取出Message消息後,取完以後將message.next給當前的message,再將message.next=null,實際上就是移除當前的message。可是在looper裏面每次在next取出message後,放到了message的sPool裏面,緩存起來方便使用。
Message就沒什麼好說的,主要存儲日常常常用的obj和what信息,以及咱們不用關心的target和callback等。
這裏會問到,一個線程會有幾個Looper,幾個Handler,以及Looper會存在線程哪裏?
一個線程一個Looper,能夠有多個Handler,Looper會存在線程的ThreadLocal對象裏,該對象是線程的緩存區
ThreadLocal
:它是和線程一一對應的,從Thread類能夠看出來,ThreadLocal是做爲Thread變量來使用。ThreadLocal只是ThreadLocalMap的一個包裝類,實現了get和set方法,而ThreadLocalMap實際是一個由Entry內部類組成的數組,Entry是繼承自弱應用,弱引用裏面放的就是ThreadLocal當前對象,Entry的value存的是當前線程要存儲的對象,value做爲Entry的成員變量。 ThreadLocal常常會問到內存泄漏的問題,從上面分析能夠發現ThreadLocalMap裏面的Entry對象存儲的ThreadLocal弱引用,而value直接做爲Entry的強引用,所以在用到了ThreadLocal的地方,防止內存泄漏,手動調用remove方法。
IntentService
是google在原生的Service基礎上經過建立子線程的Service。也就是說IntentService是專門爲android開發者提供的能在service內部實現耗時操做的service。咱們能夠經過重寫onHandleIntent
方法實現耗時操做的回調處理,並且IntentService在耗時操做完成後,會主動銷燬本身,IntentService
能夠經過屢次啓動來完成多個任務,而IntentService
只會被建立一次,每次啓動的時候只會觸發onStart方法。內部是實現了Handler異步處理耗時操做的過程,通常多用在Service中須要處理耗時操做的功能。
提問:爲何IntentService中能實現耗時操做?
HandlerThread
自己也是Thread,只是在Thread基礎上封裝上了Handler的載體,而且在run方法中建立了looper對象,這也是爲何在IntentService中能在HandlerThread中直接用handler的緣由。而咱們知道一個線程是能夠有多個handler,因此用HandlerThread更加方便咱們不用關心Handler的建立,通常用在多線程中直接處理任務。
事件分發主要分三塊:分發、攔截、消費; 當咱們觸摸到屏幕的時候,默認會先走Activity的分發,接着走ViewGroup的分發,而後到ViewGroup的攔截,後面再到View的分發事件,最後會傳到View的消費事件,若是View不消費,緊接着回傳到ViewGroup的消費事件,若是ViewGroup也不消費,最後回到View的消費事件。整個事件分發構成了一個u型結構,下面總結了分發的細節流程:
這裏會問到事件衝突的問題?
事件遵循一個原則,就是看他有沒有事件消費。好比一個LinearLayout裏面有一個Button,點擊LinearLayout會觸發到Button嗎,這裏就看LinearLayout有沒有設置點擊事件,若是有就不會傳遞到Button,若是沒有就會傳遞給Button。
性能優化
:能夠從界面、apk瘦身、混淆提及,dex分包處理,插件化動態加載模塊,開屏冷啓動提及
界面優化
:多可使用include、merge、ViewStub、約束佈局來作起,include能夠提取公共的佈局,merge能夠減小布局層次、ViewStub是使用的時候纔去建立View,減小空間的佔用、約束佈局一來能夠減小布局的層次、二來能夠提升開發的效率,在自定義view中注意view繪製過程不要作初始化的操做,通常放到view的初始化的方法裏面。
apk瘦身
:能夠用android studio的lint檢測工具檢測資源文件等
混淆
:能夠起到文件大小減小的做用,這個在實踐中能夠嘗試,混淆後能夠反編譯看看apk包的內容
dex分包
:主要是apk包的結構發生了變化,若是dex包的方法數超過了最大數,須要進行分包處理
插件化
:主要用到了java中動態代理模式和反射的思想,利用android的activity啓動流程,經過動態代理模式動態加載咱們須要插件化的activity
開屏冷啓動
:開屏冷啓動主要針對MultiDex啓動作優化,在5.0以前對dex分包是不作處理的,因此要兼容到低版本的時候須要使用MultiDex.install作兼容。而MutiDex.install將apk中的dex包獲取到,而後又壓縮成對應的zip文件,將dex文件經過反射轉換成DexFile對象、反射替換數組。因此咱們能作的優化能夠經過判斷若是jvm不支持dex分包處理,經過MutiDex.install作處理,經過監聽MutiDex.install開啓一個監聽MutiDex.install的進程activity。等到MutiDex.install處理完成後,再來處理正常的邏輯。
內存優化一般指的內存溢出,主要涉及到的問題仍是該釋放的資源,沒有及時讓GC處理器回收,一般主要表現是動畫、上下文對象、EventBus、AsycTask、Handler、單例Bitmap都會影響,一般要作的是釋放他們未終止的動做,釋放鎖定的上下文對象。
在實際項目有mvp架構的時候,須要注意內存泄漏的問題,p層若是長期持有v層的實例,致使v層的對象難以回收,而v層通常是activity或fragment做爲抽象,所以須要在p層使用v層的弱應用或是在p層中實現v層的銷燬方法,處理銷燬的邏輯。
activity界面顯示流程
:activity啓動後,不會立馬去顯示界面上的view,而是等到onResume的時候纔會真正顯示view的時機,首先會觸發windowManager.addView方法,在該方法中觸發代理對象WindowManagerGlobal的addView方法,代理對象的addView方法中建立了viewRootImpl,將setContentView中建立的decorView經過viewRootImpl的setView方法放到了viewRootImpl中,最終通過viewRootImpl一系列的方法最終調用performTraversals方法。
view的繪製
:主要指view的onMeasure、onLayout、onDraw幾個方法,其實要了解幾個方法,須要追溯到android中自己界面的結構,首先總體是一個PhoneWindow的對象,而後是一個DecorView,DecorView裏面包括一個ViewStub的ToolBar,而後下面是一個FramLayout,也就是咱們常常在Activity中setContentView中的content內容。說完了android界面的結構,下面就是說下如何繪製的,繪製首先是觸發到DecorView的onMeasure方法,它的測量規則包含了手機屏的寬高,而且測量模式是MeasureSpec.EXACTLY。因此這裏明白了DecorView(FrameLayout)的測量參數是什麼意思了,緊接着就是測量它下面的ViewGroup了,其中ViewGroup裏面有個measureChild方法去測量孩子,這裏會問到幾種父佈局的測量模式和子View的測量模式組合:
ViewGroup的測量mode | MeasureSpec.EXACTLY | MeasureSpec.AT_MOST | MeasureSpec.UNSPECIFIED |
---|---|---|---|
childDimension>0 | size=childDimension;mode=EXACTLY | size= childDimension;mode=EXACTLY | size= childDimension;mode=EXACTLY |
childDimension == LayoutParams.MATCH_PARENT | size=Viewgroup的size;mode=EXACTLY | size=Viewgroup的size;mode=AT_MOST | size=Viewgroup的size;mode=UNSPECIFIED |
childDimension == LayoutParams.WRAP_CONTENT | size=Viewgroup的size;mode=AT_MOST | size=Viewgroup的size;mode=AT_MOST | size=Viewgroup的size;mode=UNSPECIFIED |
測量處理完了以後,緊接着就是View的onLayout,其中onLayout的做用是給View固定好位置,該方法傳進來的幾個參數是相對於本身的parent的位置,左上角是(0,0)的座標。最後就是咱們的onDraw,該方法是咱們須要在畫布上畫東西的方法,通常包括畫背景、畫圖層等等。
Zygote
會分裂出系統的核心服務進程SystemServer
,也就是SystemServer
裏面包括了底層的ActivityManagerService
、PackageManagerService
、WindowManagerService
等,這些核心服務都是經過Zygote.init
啓動的,ActivityManagerService
就是咱們後面經過binder的ipc通訊機制來與客戶端ActivityThread
創建通訊的。Launcher
應用會經過startActivity
的方式啓動應用,而Intent
的獲取會通過以下幾部: (1) ActivityManagerService
會經過PackageManager的resolveIntent()
收集這個intent
對象的指向信息。 (2)指向信息被存儲在一個intent
對象中。 (3)下面重要的一步是經過grantUriPermissionLocked()
方法來驗證用戶是否有足夠的權限去調用該intent
對象指向的Activity
。 (4)若是有權限, ActivityManagerService
會檢查並在新的task中啓動目標activity
. (5)如今, 是時候檢查這個進程的ProcessRecord
是否存在了。ProcessRecord
不是null,ActivityManagerService
會建立新的進程來實例化該activity
。ActivityManagerService
調用startProcessLocked()
方法來建立新的進程, 該方法會經過前面講到的socket通道傳遞參數給Zygote進程. Zygote
孵化自身, 並調用ZygoteInit.main()
方法來實例化ActivityThread
對象並最終返回新進程的pid。ApplicationThread
,最終會觸發ApplicationThread的scheduleLaunchActivity方法,該方法將消息發送給了ActivityThread的handler對象,最終交給了Instrumentation對象建立activity。後面也就觸發一系列的生命週期方法。EventBus是一款在android開發中使用的發佈/訂閱事件的總線框架,基於觀察者模式,將事件的接收者和發送者分開,基本包括了以下幾個步驟:
註冊事件的訂閱方法
:該步驟主要是找到訂閱者下面有哪些方法須要被訂閱 訂閱操做
:將須要被訂閱的方法放到相似HashMap的數據結構中存儲起來,方便後面發送事件和取消註冊等資源的釋放的時候使用 發送事件
:該步驟首先遍歷事件隊列,而後從隊列中取出事件,而且將事件從隊列中移除,拿到事件後,判斷事件處於的什麼線程,若是是非UI線程,則須要Handler去處理,若是是的話,則直接經過反射調用被觀察的方法。 反註冊
:該步驟就沒什麼好說的,主要是上面存儲到HashMap中的被訂閱的方法的移除,釋放在內存中的資源。
just
:將同種數據源組合放到被觀察者上面
from
:將相似數組、集合的數據源放到被觀察者上面
map
:將一種數據源,轉化成另一種
flatmap
:將一種數據源,轉化成另一種數據,而且被轉化的數據是亂序排列的
concatmap
:將一種數據源,轉化成另一種數據,而且被轉化的數據是按照先前的數據源順序排序的
toList
:將數組的形式轉化成List集合
subscribeOn
:設置Observable的call方法所在的線程,也就是數據來源的線程
observeOn
:設置subscribe的call方法所在的線程,也就是數據處理的線程
filter
:在被觀察者的數據層過濾數據
onErrorResumeNext
:出錯的時候,能夠指定出錯的時候的被觀察者
retryWhen
:出錯的時候,從新走一遍被訂閱的過程
concat
:合併相同類型的被觀察者到一個被觀察者身上,有點相似集合、數組拼接數據。
zip
:處理多種不一樣結果集的數據發射,通常用得多的地方是多個網絡請求組合而後統一處理業務邏輯。 還有不少操做符就本身去看,這些操做符已經夠面試用的了。
線程鎖鎖方法
:是須要等到該線程用完了該方法才能釋放同步鎖 線程鎖鎖類對象
:是須要等到該線程用完了該類對象才能釋放同步鎖 區別
:是鎖方法的區域要小 鎖類對象包括了該類的全部屬性
AsyncTask主要是對android中java的線程池的封裝,該類中默認開啓了兩個線程池,一個線程池負責任務的排隊處理,保證任務被單個處理,另一個線程池用來專門處理任務,最後任務處理完了,交給Handler發送消息到主線程,而後Handler處理線程,交給了onPostExecute
方法。
內部過程
:
WorkerRunnable
對象,它是處理doInBackground
的Callable對象,接着建立了FutureTask
對象,它是將上面WorkerRunnable
包裝了一層的Runnable
和Future
對象,實際上線程池要執行的任務就是該WorkerRunnable
對象。SerialExecutor
對象來排隊處理FutureTask
,裏面經過ArrayDeque
來按順序取出FutureTask
,取出後交給了THREAD_POOL_EXECUTOR
對象,它是在靜態代碼塊中建立的線程池,因此說THREAD_POOL_EXECUTOR
纔是正真執行任務的關鍵地方。問題
:
AsyncTask內部會建立一個線程池?
兩個線程池,一個線程池負責排隊處理任務;另外一個線程池用來負責處理FutureTask
,也就是將上面WorkerRunnable
包裝了一層的Runnable
對象。
AsyncTask對此執行excute方法會怎樣?
直接拋出IllegalStateException
(非法狀態異常)
MVP
:主要是分離了M層和V層的代碼,經過P層來創建他們的關聯,實現M層和V層的解耦。缺點就是每增長一個功能,須要增長相應的接口回調。沒辦法,MVP的核心就是經過接口實現隔離,將相關的業務層交給了P層。
若是要細說mvp須要注意幾點:
public interface AddBookShelfContract {
interface View extends BaseContract.BaseView {
void addBookShelfSuccess(BookShelfItem... bookShelfItem);
void addBookShelfFail();
void alreadyBookShelf(BookShelfItem bookShelfItem);
}
interface Presenter extends BaseContract.BasePresenter<View> {
void addBookShelf(String tokenId, BookShelfItem... bookShelfItem);
}
}
複製代碼
MVVM
:主要是用到了觀察者模式,經過數據的改變來通知相應的View改變的過程。M層和上面的MVP中的M層是同樣的,都是網絡請求+數據緩存來實現該層的,裏面的雙V,一個指的ViewModel實現的,另一個AndroidDataBinding實現V層,ViewModel層獲取到M層的數據後,經過觀察者模式通知AndroidDataBinding在UI上的改變。缺點的話,只能吐糟下AndroidDataBinding了,在xml中寫邏輯的時候,一點提示代碼都沒有,感受徹底是在寫js似的,可讀性確定對於初級的來講仍是有點難看懂的。
觀察者模式是由一個發送者(發送者是筆者本身的稱呼,覺較之被觀察者貼切得多)和一個觀察者構成的、發送者在狀態改變時(用戶操做、程序主動改變等)主動通知全部觀察者做相應的刷新。 android中最經典要說ListView的數據源發生變化了,刷新列表的事例。在setAdapter的時候,生成一個AdapterDataSetObserver
,緊接着就是訂閱上該觀察者,該觀察者onChange
方法裏面有requestLayout
方法,該方法是觸發UI發生變化的方法。在BaseAdapter
裏面能夠看到notifyDataSetChanged
實際上觸發的是DataSetObservable
被觀察者的notifyChanged
方法,notifyChanged
會觸發AdapterDataSetObserver
的onChange
方法。因此最終會走listView的requestLayout
,最後刷新了UI。
將類的生命週期方法移交到Lifecycle中管理,實現對類的生命週期的監聽,從而在Lifecycle中處理生命週期的邏輯代碼。這裏涉及到幾個對象: LifecycleObserver接口
( Lifecycle觀察者):實現該接口的類,經過註解的方式,能夠經過被LifecycleOwner類的addObserver(LifecycleObserver o)方法註冊,被註冊後,LifecycleObserver即可以觀察到LifecycleOwner的生命週期事件。 LifecycleOwner接口
(Lifecycle持有者):實現該接口的類持有生命週期(Lifecycle對象),該接口的生命週期(Lifecycle對象)的改變會被其註冊的觀察者LifecycleObserver觀察到並觸發其對應的事件。 Lifecycle
(生命週期):和LifecycleOwner不一樣的是,LifecycleOwner自己持有Lifecycle對象,LifecycleOwner經過其Lifecycle getLifecycle()的接口獲取內部Lifecycle對象。 State
(當前生命週期所處狀態):幾種事件狀態。 Event
(當前生命週期改變對應的事件):當Lifecycle發生改變,事件狀態的回調event。
okhttp主要實現了異步、同步的網絡操做,建立了不一樣的call
對象,這裏的call對象是一個個的runnable對象,因爲咱們的任務是不少的,所以這裏有Dispatcher
包裝了線程池來處理不一樣的call
,其中該類中建立了三種隊列,分別用於存放正在執行的異步任務,同步隊列,以及準備的隊列。最後在執行每一個任務的時候,採用隊列的先進先出原則,處理每個任務,都是交給了後面的各類攔截器來處理,有請求準備的攔截器、緩存攔截器、網絡鏈接的攔截器,每個攔截器組成了一個責任鏈的形式。到最後返回response
信息。 OkHttp的底層是經過Java的Socket發送HTTP請求與接受響應的(這也好理解,HTTP就是基於TCP協議的),可是OkHttp實現了鏈接池的概念,即對於同一主機的多個請求,其實能夠公用一個Socket鏈接,而不是每次發送完HTTP請求就關閉底層的Socket,這樣就實現了鏈接池的概念。而OkHttp對Socket的讀寫操做使用的OkIo庫進行了一層封裝。
retrofit基於okHttp封裝成RESTFUL網絡請求框架,經過工廠模式配置各類參數,經過動態代理、註解實現網絡請求。retrofit利用了工廠模式,將分爲生產網絡請求執行器(callFactory)、回調方法執行器(callbackExecutor)、網絡請求適配器(CallAdapterFactory)、數據轉換器(converterFactory)等幾種工廠。 callFactory負責生產okHttp的call,你們都知道okHttp經過生成call對象完成同步和異步的http請求。
callbackExecutor經過判斷不一樣的平臺,生成對應平臺的數據回調執行器。其中android端的回調執行器是經過handler回調數據。
CallAdapterFactory是數據解析工廠,通常咱們配置json的數據解析適配器就行。
converterFactory是數據轉換的工廠,通常咱們配置Rxjava的數據轉換就行。
retrofit經過動態代理模式實現接口類配置的註解、參數解析成HTTP對象,最後經過okHttp實現網絡請求。
RxJava經過subscribeOn
指定被觀察者發生的線程,observeOn
指定觀察者發生的線程。其中Schedulers.IO生成的是IoScheduler
。經過觀察者與被觀察者訂閱的過程當中,首先會觸發被觀察者的subscribeActual
方法,在該方法中,能夠看到最終會走scheduler
的schedule
方法,因此上面提到的IoScheduler
實際是調用了它的schedule
方法,最終會在NewThreadWorker
裏面生成ScheduledExecutorService
對象,而ScheduledExecutorService
實際是由ScheduledThreadPoolExecutor
建立的一個核心線程,最大線程個數是Integer.MAX_VALUE的線程池。最終會由ScheduledThreadPoolExecutor
的submit
或schedule
方法執行傳過來的Runnable對象,而Runnable執行的是被觀察者的subscribe
方法。因此解釋了被觀察者的subscribe
方法是在子線程中執行的。
observeOn
是觀察者發生的線程,AndroidSchedulers.mainThread()
實質是HandlerScheduler
對象,而在觀察者部分,最終觀察部分會走Scheduler的scheduleDirect
方法,而HandlerScheduler
的該方法裏面包裝了一個ScheduledRunnable
對象,經過主線程的handler.postDelayed處理這個runnable對象。
RecyclerView使用了強大的分工操做,顯示、排版由LayoutManager處理,數據顯示由adapter處理,item上下左右動態加入繪製由ItemDecoration處理,item的動畫由ItemAnimator處理。面試主要分析recyclerView緩存,recyclerView緩存是由內部類Recycler維護,其中一級緩存有mAttachedScrap
,裏面放的都是當前屏幕正在顯示的viewHolder的緩存,二級緩存是mCachedViews
,裏面放的都是移出到屏幕外的viewHolder緩存,mRecyclerPool
是recyclerView的三級緩存,通常用在RecyclerView嵌套RecyclerView的時候用獲得,好比外層的RecyclerView的item中有RecyclerView,那麼裏面的RecyclerView經過共用外層的RecyclerView的RecyclerPool來減小裏面RecyclerView的ViewHolder建立。
binder機制是android端進程間通訊的基石,採用aidl的ipc通訊方式,咱們能夠利用它來定義兩個進程相互通訊的接口。他是基於Service實現的一種線程間通訊機制。它的本質是C/S架構的,須要一個服務器端,一個客戶端。 AIDL通訊方式裏面有四個對象,一個是IInterface,專門用來負責接口的調度,Stub用來負責通訊的響應和發送給service端的數據,Proxy負責兩個進程通訊的包裝,算是間接調用Stub的包裝類,service是服務端處理數據的關鍵類。用一張圖來表示以下:
android jetpack是google專門爲開發者快速開發app的一套組件,快速搭建mvvm框架的實現,其中包括Lifecyle、LiveData、ViewModel、Room、DadaBinding、Navigation、Paging、WorkManager等一系列優秀的框架。
Lifecycle:實現和activity、fragment生命週期感知的框架,實現數據層和view層銷燬的時候解綁。原理是Lifecycler爲每一個活動組件添加了一個沒有界面的Fragment,利用Fragment週期會根據活動聲明週期變化的特性實現的特性,從而實現生命週期的感知,而後根據註解的Event查找執行相應的方法。
LiveData:提供了一種數據改變的同時,主動去告訴ui,讓ui層作出相應的邏輯判斷。原理是內部保存了LifecycleOwner和Observer,利用LifecycleOwner感知並處理聲明中期的變化,Observer在數據改變時遍歷全部觀察者並回調方法。
ViewModel:它是咱們view層和model層的橋樑,是數據驅動界面的關鍵地方,也是咱們ui層在數據丟失的狀況下,viewModel還能繼續保持原有的數據,原理是將數據保存到ViewModel中,而後爲活動中添加一個HolderFragment,HolderFragment中保存了ViewStore的實例,ViewStore中使用Map保存了ViewModel,從而在活動從新建立時獲取到原來的ViewModel。
Room:是model層本地數據庫的框架,經過實體映射到對應的db表結構,將實體映射到db關係型數據庫裏面。跟greendao差很少,room數據庫版本升級數據遷移比greendao遷移要麻煩,我的仍是比較喜歡greendao來實現本地數據庫。 DadaBinding:是一個能夠經過在xml佈局文件中實現ui邏輯的框架,而且它的ui層和數據層雙向驅動仍是挺不錯的。
Navigation:是後面新出來的可視化管理fragment的組件,經過在xml中配置fragment之間跳轉的關係。
kotlin使用了一組新的語法糖,kotlin不讓變量初始化空的類型,強大的非空設計思想比java要人性化,在代碼編寫階段就有提示開發者的好處。還有它的內聯函數,函數體做爲返回值的各類簡寫方式使更多的人願意接受kotlin。它的協成開發比較好的控制線程之間切換的多層嵌套的問題,以及它簡潔的語法,比較受開發者青睞。
好了,大概android面試的android篇就寫這麼多。若是你們以爲還有那些要補上能夠留言我!!!