android面試筆試總結(android篇)

Activity中的幾種啓動模式

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=singleTopbash

FLAG_ACTIVITY_NEW_TASK服務器

  • 在相同taskAffinity狀況下:啓動activity是沒有任何做用的。

  • 在不一樣taskAffinity狀況下: 若是啓動不一樣棧中的activity已經存在了某一個棧中的activity,那麼此時是啓動不了該activity的,由於棧中已經存在了該activity;若是棧中不存在該要啓動的activity,那麼會啓動該acvitity,而且將該activity放入該棧中。

FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOP一塊兒使用,而且要啓動的activity的taskAffinity和當前activity的taskAffinity不同纔會和singleTask同樣的效果,由於要啓動的activity和原先的activity不在同一個taskAffinity中,因此能啓動該activity,這個地方有點繞,寫個簡單的公式:

  • FLAG_ACTIVITY_NEW_TASK若是啓動同一個不一樣taskAffinity的activity纔會有效果。
  • FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOP若是一塊兒使用要開啓的activity和如今的activity處於同一個taskAffinity,那麼效果仍是跟沒加FLAG_ACTIVITY_NEW_TASK是同樣的效果。
  • FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOP啓動和如今的activity不是同一個taskAffinity纔會和singleTask同樣的效果。

FLAG_ACTIVITY_CLEAR_TASK

  • 在相同taskAffinity狀況下:和FLAG_ACTIVITY_NEW_TASK一塊兒使用,啓動activity是沒有任何做用的。
  • 在不一樣taskAffinity狀況下:和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跳轉。

android消息機制

消息機制指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

IntentService是google在原生的Service基礎上經過建立子線程的Service。也就是說IntentService是專門爲android開發者提供的能在service內部實現耗時操做的service。咱們能夠經過重寫onHandleIntent方法實現耗時操做的回調處理,並且IntentService在耗時操做完成後,會主動銷燬本身,IntentService能夠經過屢次啓動來完成多個任務,而IntentService只會被建立一次,每次啓動的時候只會觸發onStart方法。內部是實現了Handler異步處理耗時操做的過程,通常多用在Service中須要處理耗時操做的功能。

提問:爲何IntentService中能實現耗時操做?

  • 在onCreate中,經過HandlerThread來開啓一條線程,而HandlerThread線程中會跟咱們日常用的Handler不太同樣,在run方法中建立了looper對象,因此HandlerThread能讓IntentService在子線程中使用handler達到耗時操做。

HandlerThread

HandlerThread自己也是Thread,只是在Thread基礎上封裝上了Handler的載體,而且在run方法中建立了looper對象,這也是爲何在IntentService中能在HandlerThread中直接用handler的緣由。而咱們知道一個線程是能夠有多個handler,因此用HandlerThread更加方便咱們不用關心Handler的建立,通常用在多線程中直接處理任務。

事件分發

事件分發主要分三塊:分發、攔截、消費; 當咱們觸摸到屏幕的時候,默認會先走Activity的分發,接着走ViewGroup的分發,而後到ViewGroup的攔截,後面再到View的分發事件,最後會傳到View的消費事件,若是View不消費,緊接着回傳到ViewGroup的消費事件,若是ViewGroup也不消費,最後回到View的消費事件。整個事件分發構成了一個u型結構,下面總結了分發的細節流程:

  • 若是ViewGroup的dispatchTouchEvent返回true或false,touch事件不會往子view中傳遞,false的時候只會觸發action_down,ViewGroup的onTouchEvent事件也不會被觸發。只有在返回super.dispatchTouchEvent時候touch事件纔會傳遞到子view。
  • 若是ViewGroup的onInterceptTouchEvent返回false或者super.onInterceptTouchEvent時,touch事件會傳遞到子view。返回true事件不會向下傳遞,交給本身的ontouchEvent處理。
  • 若是view的dispatchTouchEvent返回true或false,touch事件不會傳給本身的ontouchEvent事件,返回false,只會觸發action_down,move和up不會觸發;返回true,纔會觸發move和up。返回super.dispatchTouchEvent,touch事件纔會交給本身的onTouchEvent處理。
  • 若是view的ontouchEvent返回false,只會有action_down事件,touch事件交給上一層處理,若是返回true纔會消費,事件不會向上傳遞,若是返回super.ontouchEvent,得看clickable是否是返回true。

這裏會問到事件衝突的問題?

事件遵循一個原則,就是看他有沒有事件消費。好比一個LinearLayout裏面有一個Button,點擊LinearLayout會觸發到Button嗎,這裏就看LinearLayout有沒有設置點擊事件,若是有就不會傳遞到Button,若是沒有就會傳遞給Button。

view事件分發流程圖

android性能優化、內存優化

性能優化:能夠從界面、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層的銷燬方法,處理銷燬的邏輯。

View的繪製

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,該方法是咱們須要在畫布上畫東西的方法,通常包括畫背景、畫圖層等等。

App啓動流程

  • 從Linux內核系統到init進程的分裂,以及後面會啓動一個叫Zygote的進程開始,而Zygote會分裂出系統的核心服務進程SystemServer,也就是SystemServer裏面包括了底層的ActivityManagerServicePackageManagerServiceWindowManagerService等,這些核心服務都是經過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。
  • 隨後就是咱們熟悉的ActivityThread.main方法經過Looper.prepare和Looper.loop方法開啓消息循環
  • 緊接着就是建立Application對象的過程,先是建立好ContextImpl對象,而後經過makeApplication方法將app進程與Application創建聯繫,這裏的Application建立交給了Instrumentation的對象,其實後面activity的建立,生命週期的回調都是經過它來觸發的。
  • 建立完Application後,緊接着就是咱們熟悉的Activity,activity的建立一樣交給了Instrumentation對象,上面說過ActivityManagerService會將攜帶的Intent對象交給了Lanucher應用,Lanucher的startActivity通過一系列的操做,最終會走Instrumentation的execStartActivity方法,該方法裏面會去請求ActivityManagerService服務,最終經過binder通訊將信息傳給了客戶端的ApplicationThread,最終會觸發ApplicationThread的scheduleLaunchActivity方法,該方法將消息發送給了ActivityThread的handler對象,最終交給了Instrumentation對象建立activity。後面也就觸發一系列的生命週期方法。

Eventbus原理

EventBus是一款在android開發中使用的發佈/訂閱事件的總線框架,基於觀察者模式,將事件的接收者和發送者分開,基本包括了以下幾個步驟:

註冊事件的訂閱方法:該步驟主要是找到訂閱者下面有哪些方法須要被訂閱 訂閱操做:將須要被訂閱的方法放到相似HashMap的數據結構中存儲起來,方便後面發送事件和取消註冊等資源的釋放的時候使用 發送事件:該步驟首先遍歷事件隊列,而後從隊列中取出事件,而且將事件從隊列中移除,拿到事件後,判斷事件處於的什麼線程,若是是非UI線程,則須要Handler去處理,若是是的話,則直接經過反射調用被觀察的方法。 反註冊:該步驟就沒什麼好說的,主要是上面存儲到HashMap中的被訂閱的方法的移除,釋放在內存中的資源。

Rxjava的操做符有哪些,說說他們的做用

just:將同種數據源組合放到被觀察者上面

from:將相似數組、集合的數據源放到被觀察者上面

map:將一種數據源,轉化成另一種

flatmap:將一種數據源,轉化成另一種數據,而且被轉化的數據是亂序排列的

concatmap:將一種數據源,轉化成另一種數據,而且被轉化的數據是按照先前的數據源順序排序的

toList:將數組的形式轉化成List集合

subscribeOn:設置Observable的call方法所在的線程,也就是數據來源的線程

observeOn:設置subscribe的call方法所在的線程,也就是數據處理的線程

filter:在被觀察者的數據層過濾數據

onErrorResumeNext:出錯的時候,能夠指定出錯的時候的被觀察者

retryWhen:出錯的時候,從新走一遍被訂閱的過程

concat:合併相同類型的被觀察者到一個被觀察者身上,有點相似集合、數組拼接數據。

zip:處理多種不一樣結果集的數據發射,通常用得多的地方是多個網絡請求組合而後統一處理業務邏輯。 還有不少操做符就本身去看,這些操做符已經夠面試用的了。

線程鎖 鎖方法和類對象啥的有啥區別

線程鎖鎖方法:是須要等到該線程用完了該方法才能釋放同步鎖 線程鎖鎖類對象:是須要等到該線程用完了該類對象才能釋放同步鎖 區別:是鎖方法的區域要小 鎖類對象包括了該類的全部屬性

AsyncTask原理

AsyncTask主要是對android中java的線程池的封裝,該類中默認開啓了兩個線程池,一個線程池負責任務的排隊處理,保證任務被單個處理,另一個線程池用來專門處理任務,最後任務處理完了,交給Handler發送消息到主線程,而後Handler處理線程,交給了onPostExecute方法。

內部過程:

  • AsyncTask初始化階段建立了WorkerRunnable對象,它是處理doInBackground的Callable對象,接着建立了FutureTask對象,它是將上面WorkerRunnable包裝了一層的RunnableFuture對象,實際上線程池要執行的任務就是該WorkerRunnable對象。
  • 在執行任務過程當中,經過SerialExecutor對象來排隊處理FutureTask,裏面經過ArrayDeque來按順序取出FutureTask,取出後交給了THREAD_POOL_EXECUTOR對象,它是在靜態代碼塊中建立的線程池,因此說THREAD_POOL_EXECUTOR纔是正真執行任務的關鍵地方。
  • 執行完後,剩下的就是主線程的Handler將消息發送到主線程去處理。

問題:

  • AsyncTask內部會建立一個線程池?

    兩個線程池,一個線程池負責排隊處理任務;另外一個線程池用來負責處理FutureTask,也就是將上面WorkerRunnable包裝了一層的Runnable對象。

  • AsyncTask對此執行excute方法會怎樣?

    直接拋出IllegalStateException(非法狀態異常)

說說MVP和MVVM的特色

MVP:主要是分離了M層和V層的代碼,經過P層來創建他們的關聯,實現M層和V層的解耦。缺點就是每增長一個功能,須要增長相應的接口回調。沒辦法,MVP的核心就是經過接口實現隔離,將相關的業務層交給了P層。

若是要細說mvp須要注意幾點:

  • p層的邏輯處理單一的功能,不要融合一個模塊下的增刪改查的整個功能。
  • 因爲p層持有了v層的引用,一般在p層使用弱引用來持有view層實例,在p層銷燬的時候須要將v層的引用銷燬掉。
  • 契合類指的p層和v層的接口類放在一個contract接口類中,契合類方便管理業務層的功能,將單個功能放到一個contract契合類中。好比咱們有一個添加書架的功能:
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中用到的觀察者模式有哪些地方

觀察者模式是由一個發送者(發送者是筆者本身的稱呼,覺較之被觀察者貼切得多)和一個觀察者構成的、發送者在狀態改變時(用戶操做、程序主動改變等)主動通知全部觀察者做相應的刷新。 android中最經典要說ListView的數據源發生變化了,刷新列表的事例。在setAdapter的時候,生成一個AdapterDataSetObserver,緊接着就是訂閱上該觀察者,該觀察者onChange方法裏面有requestLayout方法,該方法是觸發UI發生變化的方法。在BaseAdapter裏面能夠看到notifyDataSetChanged實際上觸發的是DataSetObservable被觀察者的notifyChanged方法,notifyChanged會觸發AdapterDataSetObserveronChange方法。因此最終會走listView的requestLayout,最後刷新了UI。

說說google新出的Lifecycle框架

將類的生命週期方法移交到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原理

okhttp主要實現了異步、同步的網絡操做,建立了不一樣的call對象,這裏的call對象是一個個的runnable對象,因爲咱們的任務是不少的,所以這裏有Dispatcher包裝了線程池來處理不一樣的call,其中該類中建立了三種隊列,分別用於存放正在執行的異步任務,同步隊列,以及準備的隊列。最後在執行每一個任務的時候,採用隊列的先進先出原則,處理每個任務,都是交給了後面的各類攔截器來處理,有請求準備的攔截器、緩存攔截器、網絡鏈接的攔截器,每個攔截器組成了一個責任鏈的形式。到最後返回response信息。 OkHttp的底層是經過Java的Socket發送HTTP請求與接受響應的(這也好理解,HTTP就是基於TCP協議的),可是OkHttp實現了鏈接池的概念,即對於同一主機的多個請求,其實能夠公用一個Socket鏈接,而不是每次發送完HTTP請求就關閉底層的Socket,這樣就實現了鏈接池的概念。而OkHttp對Socket的讀寫操做使用的OkIo庫進行了一層封裝。

Retrofit原理

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 的線程切換原理

  • RxJava經過subscribeOn指定被觀察者發生的線程,observeOn指定觀察者發生的線程。其中Schedulers.IO生成的是IoScheduler。經過觀察者與被觀察者訂閱的過程當中,首先會觸發被觀察者的subscribeActual方法,在該方法中,能夠看到最終會走schedulerschedule方法,因此上面提到的IoScheduler實際是調用了它的schedule方法,最終會在NewThreadWorker裏面生成ScheduledExecutorService對象,而ScheduledExecutorService實際是由ScheduledThreadPoolExecutor建立的一個核心線程,最大線程個數是Integer.MAX_VALUE的線程池。最終會由ScheduledThreadPoolExecutorsubmitschedule方法執行傳過來的Runnable對象,而Runnable執行的是被觀察者的subscribe方法。因此解釋了被觀察者的subscribe方法是在子線程中執行的。

  • observeOn是觀察者發生的線程,AndroidSchedulers.mainThread()實質是HandlerScheduler對象,而在觀察者部分,最終觀察部分會走Scheduler的scheduleDirect方法,而HandlerScheduler的該方法裏面包裝了一個ScheduledRunnable對象,經過主線程的handler.postDelayed處理這個runnable對象。

RecyclerView源碼、緩存分析

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機制

binder機制是android端進程間通訊的基石,採用aidl的ipc通訊方式,咱們能夠利用它來定義兩個進程相互通訊的接口。他是基於Service實現的一種線程間通訊機制。它的本質是C/S架構的,須要一個服務器端,一個客戶端。 AIDL通訊方式裏面有四個對象,一個是IInterface,專門用來負責接口的調度,Stub用來負責通訊的響應和發送給service端的數據,Proxy負責兩個進程通訊的包裝,算是間接調用Stub的包裝類,service是服務端處理數據的關鍵類。用一張圖來表示以下:

圖片轉載

Android Jetpack

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之間跳轉的關係。

系統打包通過了哪幾個流程

  • 打包資源文件,經過AAPT(Android Asset Packaging Tool)打包成R.java類(資源索引表)以及.arsc資源文件。
  • 處理AIDL文件,檢查app中是否有aidl文件,若是有會經過aidl工具(源碼位於system/tools/aidl)打包成java接口類
  • 編譯R.java源碼部分以及aidl.java經過javac生成對應的.class文件。
  • 將上面生成的.class文件和第三方jar或者library經過dx工具打包生成dex文件。
  • 生成未簽名的apk,包括apkbuilder工具將全部沒有編譯的資源、.arsc資源、.dex文件打包到一個完成apk文件中
  • 生成簽名的apk,包括jarsigner工具對未簽名的apk驗證簽名。獲得一個簽名後的apk(signed.apk)
  • zipAlign工具對齊上面簽名的apk文件。

Kotlin

kotlin使用了一組新的語法糖,kotlin不讓變量初始化空的類型,強大的非空設計思想比java要人性化,在代碼編寫階段就有提示開發者的好處。還有它的內聯函數,函數體做爲返回值的各類簡寫方式使更多的人願意接受kotlin。它的協成開發比較好的控制線程之間切換的多層嵌套的問題,以及它簡潔的語法,比較受開發者青睞。

好了,大概android面試的android篇就寫這麼多。若是你們以爲還有那些要補上能夠留言我!!!

相關文章
相關標籤/搜索