線程池原理
參考:
Java 線程池原理分析
線程池工作原理:
1、線程數(shù)量小于 corePoolSize,直接創(chuàng)建新線程處理新的任務(wù)
2、線程數(shù)量大于等于 corePoolSize,workQueue 未滿,則緩存新任務(wù)
3、線程數(shù)量大于等于 corePoolSize,但小于 maximumPoolSize,且 workQueue 已滿。則創(chuàng)建新線程處理新任務(wù)
4、線程數(shù)量大于等于 maximumPoolSize,且 workQueue 已滿,則使用拒絕策略處理新任務(wù)
如何快速定位ANR
參考:
巧妙定位ANR問題
1、拿到/data/anr/trace.txt對應(yīng)的文件,然后搜索關(guān)鍵字ANR。
2、搜索"Dalvik Thread"關(guān)鍵字找到主線程
Glide緩存與解碼復(fù)用
Glide擁有4級緩存
1、活動資源:如果當(dāng)前對應(yīng)的圖片資源正在使用,則這個圖片會被Glide放入活動緩存。
2、內(nèi)存緩存:如果圖片最近被加載過,并且當(dāng)前沒有使用這個圖片,則會被放入內(nèi)存中
3、解碼過的資源類型: 被解碼后的圖片寫入磁盤文件中,解碼的過程可能修改了圖片的參數(shù)(如:inSampleSize、inPreferredConfig)
4、原始數(shù)據(jù): 圖片原始數(shù)據(jù)在磁盤中的緩存(從網(wǎng)絡(luò)、文件中直接獲得的原始數(shù)據(jù))
Bitmap復(fù)用
Glide中,在每次解析一張圖片為Bitmap的時候(磁盤緩存、網(wǎng)絡(luò)/文件)會從其BitmapPool中查找一個可被復(fù)用的Bitmap。
BitmapPool是Glide中的Bitmap復(fù)用池,同樣適用LRU來進行管理。
當(dāng)一個Bitmap從內(nèi)存緩存 被動 的被移除(內(nèi)存緊張、達到maxSize)的時候并不會被recycle。而是加入這個BitmapPool,只有從這個BitmapPool 被動的被移除的時候,Bitmap的內(nèi)存才會真正被recycle釋放。
Android Dalvik與ART的區(qū)別
Dalvik和JVM的關(guān)系
1、Dalvik是基于寄存器的,而JVM是基于棧的。
2、Dalvik運行dex文件,而JVM運行java字節(jié)碼。
ART 的機制與 Dalvik 不同。在Dalvik下,應(yīng)用每次運行的時候,字節(jié)碼都需要通過即時編譯器(just in time ,JIT)轉(zhuǎn)換為機器碼,這會拖慢應(yīng)用的運行效率,而在ART 環(huán)境中,應(yīng)用在第一次安裝的時候,字節(jié)碼就會預(yù)先編譯成機器碼,使其成為真正的本地應(yīng)用。這個過程叫做預(yù)編譯(AOT,Ahead-Of-Time)。這樣的話,應(yīng)用的啟動(首次)和執(zhí)行都會變得更加快速。Android 4.4引入。
優(yōu)點:
1、系統(tǒng)性能的顯著提升。
2、應(yīng)用啟動更快、運行更快、體驗更流暢、觸感反饋更及時。
3、更長的電池續(xù)航能力。
4、支持更低的硬件。
缺點:
1.機器碼占用的存儲空間更大,字節(jié)碼變?yōu)闄C器碼之后,可能會增加10%-20%(不過在應(yīng)用包中,可執(zhí)行的代碼常常只是一部分。比如最新的 Google+ APK 是 28.3 MB,但是代碼只有 6.9 MB。)
2.應(yīng)用的安裝時間會變長。
Loop為什么不會阻塞主線程,死循環(huán)為什么不會耗盡cpu資源
ActivityThread thread = new ActivityThread();
thread.attach(false);//建立Binder通道 (創(chuàng)建新線程)
主線程的死循環(huán)一直運行是不是特別消耗CPU資源呢? 其實不然,這里就涉及到Linux pipe/epoll機制,簡單說就是在主線程的MessageQueue沒有消息時,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此時主線程會釋放CPU資源進入休眠狀態(tài),直到下個消息到達或者有事務(wù)發(fā)生,通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作。這里采用的epoll機制,是一種IO多路復(fù)用機制,可以同時監(jiān)控多個描述符,當(dāng)某個描述符就緒(讀或?qū)懢途w),則立刻通知相應(yīng)程序進行讀或?qū)懖僮?,本質(zhì)同步I/O,即讀寫是阻塞的。 所以說,主線程大多數(shù)時候都是處于休眠狀態(tài),并不會消耗大量CPU資源。
xml布局中Include、ViewStub、Merge的區(qū)別
Include:解決布局復(fù)用、如果對include設(shè)置了id有可能導(dǎo)致找不到layout根布局的id
ViewStub:ViewStub就是一個寬高都為0的一個View,它默認是不可見的。
只有通過調(diào)用 setVisibility() 函數(shù)或者 Inflate() 函數(shù)才會將其要裝載的目標(biāo)布局給加載出來,從而達到延遲加載的效果。
在ViewStub布局可顯示之前,系統(tǒng)不會消耗資源去實例化里面的布局,可以節(jié)省系統(tǒng)資源消耗
Merge:merge它可以刪減多余的層級,優(yōu)化UI。
例如你的主布局文件是垂直的LinearLayout,這時使用include將 my_layout.xml 引入進來。
新布局也是垂直的LinearLayout,那么這個新的LinearLayout就沒有任何意義了。使用的話反而增加反應(yīng)時間。這時可以使用<merge/>標(biāo)簽優(yōu)化。merge 原理就是在解析xml時候,如果是 <merge/> 標(biāo)簽,那么直接將其中的子元素添加到merge 標(biāo)簽parent中,這樣就保證了不會引入額外的層級
view的繪制原理
從ViewRootImpl的performTraversals()開始被觸發(fā),遍歷view的onMeasure、onLayout、onDraw。
onMeasure:MeasureSpec 三種模式。32位,前2位代表模式,后2位代表size。
final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
lp.width);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec);
int size = Math.max(0, specSize - padding);
int resultSize = 0;
int resultMode = 0;
switch (specMode) {
// Parent has imposed an exact size on us
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
// Parent has imposed a maximum size on us
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
// Child wants a specific size... so be it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size, but our size is not fixed.
// Constrain child to not be bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break;
// Parent asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
//noinspection ResourceType
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
Android為什么會出現(xiàn)卡頓
1、渲染性能,布局層級過深。60fps即一秒鐘需要渲染60幀,每個16ms發(fā)出VSYNC信號,掉幀。
2、垃圾回收會阻塞線程。所以避免頻繁的創(chuàng)建對象和回收對象。不要在生命周期短的方法中創(chuàng)建對象,比如onDraw中創(chuàng)建Paint對象。
3、動畫過于復(fù)雜,超過16ms。
JVM內(nèi)存結(jié)構(gòu)
1、線程私有:程序計數(shù)器、jvm虛擬機棧、本地方法棧
2、線程共有:堆、方法區(qū)(包含常量池)(沒有明確的規(guī)范)
垃圾回收的判斷標(biāo)準(zhǔn):
1、計數(shù)法:循環(huán)依賴的對象不能被回收
2、根查找法(目前采用)
垃圾回收算法:
1、標(biāo)記清理:會造成內(nèi)存碎片
2、復(fù)制收集法:分成2個大小相等的區(qū),將在使用的對象復(fù)制到應(yīng)一塊內(nèi)存中,一次性清理未使用的對象 會造成內(nèi)存浪費
3、標(biāo)記 整理 清理
4、分代算法:分成新生代、老年代、持久代。
新生代按8:1:1分成edge和survival區(qū)
Flutter的skia渲染引擎和Android原生渲染引擎的差別
目前,Skia已然是Android官方的圖像渲染引擎了,因此Flutter Android SDK無需內(nèi)嵌Skia引擎就可以獲得天然的Skia支持;
Dart因為同時支持JIT和AOT,所以既開發(fā)效率高,又運行速度好、執(zhí)行性能高.
FlutterView集成FrameLayout,內(nèi)部持有FlutterSurfaceView繼承SurfaceView。
View和SurfaceView的區(qū)別:
1、View適用于主動更新的情況,而SurfaceView則適用于被動更新的情況,比如頻繁刷新界面。
2、View在主線程中對頁面進行刷新,而SurfaceView則開啟一個子線程來對頁面進行刷新。
3、View在繪圖時沒有實現(xiàn)雙緩沖機制,SurfaceView在底層機制中就實現(xiàn)了雙緩沖機制。
雙緩沖技術(shù)是游戲開發(fā)中的一個重要的技術(shù)。當(dāng)一個動畫爭先顯示時,程序又在改變它,前面還沒有顯示完,程序又請求重新繪制,這樣屏幕就會不停地閃爍。而雙緩沖技術(shù)是把要處理的圖片在內(nèi)存中處理好之后,再將其顯示在屏幕上。雙緩沖主要是為了解決 反復(fù)局部刷屏帶來的閃爍。把要畫的東西先畫到一個內(nèi)存區(qū)域里,然后整體的一次性畫出來。
sync和lock的區(qū)別和原理。

synchronized是在JVM層面上實現(xiàn)的,不但可以通過一些監(jiān)控工具監(jiān)控synchronized的鎖定,而且在代碼執(zhí)行時出現(xiàn)異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現(xiàn)的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中。
存儲優(yōu)化
SharedPreferences:
1、跨進程不安全
2、加載緩慢
3、全量寫入
4、卡頓 apply異步寫入在崩潰火其他異常情況下會導(dǎo)致數(shù)據(jù)丟失。
Protocol Buffers:
1、性能。使用了二進制編碼壓縮,相比 JSON 體積更小,編解碼速度也更快,感興趣的同學(xué)可以參考protocol-buffers 編碼規(guī)則
2、兼容性。跨語言和前后兼容性都不錯,也支持基本類型的自動轉(zhuǎn)換,但是不支持繼承與引用類型
3、使用成本。Protocol Buffers 的開發(fā)成本很高,需要定義.proto 文件,并用工具生成對應(yīng)的輔助類。輔助類特有一些序列化的輔助方法,所有要序列化的對象,都需要先轉(zhuǎn)化為輔助類的對象,這讓序列化代碼跟業(yè)務(wù)代碼大量耦合,是侵入性較強的一種方式。
sqlite:
便于管理,除非保存的數(shù)據(jù)比較大否則不建議使用。
Binder
Binder IPC 機制中涉及到的內(nèi)存映射通過 mmap() 來實現(xiàn),mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法。內(nèi)存映射簡單的講就是將用戶空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間。映射關(guān)系建立后,用戶對這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對這段區(qū)域的修改也能直接反應(yīng)到用戶空間。
內(nèi)存映射能減少數(shù)據(jù)拷貝次數(shù),實現(xiàn)用戶空間和內(nèi)核空間的高效互動。兩個空間各自的修改能直接反映在映射的內(nèi)存區(qū)域,從而被對方空間及時感知。也正因為如此,內(nèi)存映射能夠提供對進程間通信的支持。
一次完整的 Binder IPC 通信過程通常是這樣:
1.首先 Binder 驅(qū)動在內(nèi)核空間創(chuàng)建一個數(shù)據(jù)接收緩存區(qū);
2.接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進程用戶空間地址的映射關(guān)系;
3.發(fā)送方進程通過系統(tǒng)調(diào)用 copyfromuser() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),由于內(nèi)核緩存區(qū)和接收進程的用戶空間存在內(nèi)存映射,因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了接收進程的用戶空間,這樣便完成了一次進程間的通信。
AIDL:
IBinder : IBinder 是一個接口,代表了一種跨進程通信的能力。只要實現(xiàn)了這個借口,這個對象就能跨進程傳輸。
IInterface : IInterface 代表的就是 Server 進程對象具備什么樣的能力(能提供哪些方法,其實對應(yīng)的就是 AIDL 文件中定義的接口)
Binder : Java 層的 Binder 類,代表的其實就是 Binder 本地對象。BinderProxy 類是 Binder 類的一個內(nèi)部類,它代表遠程進程的 Binder 對象的本地代理;這兩個類都繼承自 IBinder, 因而都具有跨進程傳輸?shù)哪芰?;實際上,在跨越進程的時候,Binder 驅(qū)動會自動完成這兩個對象的轉(zhuǎn)換。
Stub : AIDL 的時候,編譯工具會給我們生成一個名為 Stub 的靜態(tài)內(nèi)部類;這個類繼承了 Binder, 說明它是一個 Binder 本地對象,它實現(xiàn)了 IInterface 接口,表明它具有 Server 承諾給 Client 的能力;Stub 是一個抽象類,具體的 IInterface 的相關(guān)實現(xiàn)需要開發(fā)者自己實現(xiàn)。
1、創(chuàng)建實體類Book實現(xiàn)Parcelable接口
2、創(chuàng)建接口BookManager.aidl并提供相應(yīng)的方法
3、編寫服務(wù)端代碼AIDLService extends Service。內(nèi)部創(chuàng)建BookManager.Stub對象。并重寫服務(wù)端的方法??蛻艚壎╯ervice并與服務(wù)端進行通信。
APT
HashMap 和 HashTable 以及 CurrentHashMap 的區(qū)別。
一般來說,這三個東西基本在面試中 70% 會被問到,而問的方向也不太一樣。比如初級的問法是講講它們之前的區(qū)別,這個我想沒什么難度,大多數(shù)人還是知道主要核心區(qū)別是并發(fā)上的處理。此外,內(nèi)部數(shù)據(jù)結(jié)構(gòu)的實現(xiàn)、擴容、存取操作這些問題應(yīng)該是很老生常談了,這并沒有什么好說的,大多數(shù)人也都知道。稍微問的深一點的可能會在下面這些點上出問題。哈希碰撞,哈希計算,哈希映射,為什么是頭插法,擴容為什么是 2 的冪次等這樣的問題。
synchronized 和 volatile 、ReentrantLock 、CAS 的區(qū)別。
這個問題被問頻率不在 HashMap 之下,因為并發(fā)編程,真的很重要。能問到這幾個點的方式真的是太多了,我們能發(fā)揮的空間也同樣很大。CAS 的 ABA 問題?上面幾個東西的特性?使用場景?大概我不用再例舉了吧?對了,我多次被問到的一個問題是:synchronized 修飾實例方法和修飾靜態(tài)方法有啥不一樣。
JVM 類加載機制、垃圾回收算法對比、Java 虛擬機結(jié)構(gòu)等。
這三個問題大概出現(xiàn)概率 40%,基本只需要看我每日一問系列的推文就差不多了吧,希望更清楚明白的可以直接看《深入理解 Java 虛擬機》。當(dāng)你講到分代回收算法的時候,不免會被追問到新生對象是怎么從年輕代到老年代的,以及可以作為 root 結(jié)點的對象有哪些兩個問題。
Java 的四大引用
四大引用面試出現(xiàn)概率比我想象中要高,我原本以為就強引用、軟引用、弱引用、虛引用這四個玩意兒沒啥可講的。實際上也確實沒啥好講的,稍微問的深一些的面試官會和內(nèi)存泄漏檢測原理以及垃圾回收糅雜在一起。
Java 的泛型,<? super T> 和 <? extends T> 的區(qū)別。
<? extends T>:是指 上界通配符(Upper Bounds Wildcards) 只有讀取權(quán)限 沒有寫入權(quán)限
<? super T>:是指 下界通配符(Lower Bounds Wildcards)只有寫入權(quán)限 沒有讀取權(quán)限
頻繁往外讀取內(nèi)容的,適合用上界Extends。
經(jīng)常往里插入的,適合用下界Super。
Java 線程有哪些狀態(tài),有哪些鎖,各種鎖的區(qū)別。
線程狀態(tài):新建、就緒、運行、阻塞、死亡
對應(yīng)的方法:
進入就緒狀態(tài):star
運行狀態(tài):由CPU進行調(diào)控
阻塞狀態(tài):sleep()、wait()、join()、suspend()(已廢棄)
死亡狀態(tài):run()方法的正常退出
線程鎖:
1、synchronized必須有對應(yīng)的鎖對象,ReentrantLock沒有對應(yīng)的鎖對象,這兩個鎖之間無論如何都不會互斥。
2、ReentrantLock提供了更多功能,比如tryLock()、設(shè)置鎖的公平性、是否可以接收中斷信號等。3、synchronized沒有對應(yīng)的功能。synchronized關(guān)鍵字是從虛擬機層次上保證互斥的,而ReentrantLock是從代碼層次上保證互斥的。
sleep 、wait、yield 的區(qū)別,wait 的線程如何喚醒它?
wait和sleep的區(qū)別 面試 wait和notify yield
很基本的區(qū)別:wait是object類的方法,sleep、yield是thread類的方法。
wait釋放cpu資源,同時釋放鎖
sleep也釋放cpu資源,但不釋放鎖
wait需要搭配notify
final 、finally、finalize 區(qū)別。
final 用于申明屬性,方法和類,表示屬性不可變,方法不可以被覆蓋,類不可以被繼承。
finally 是異常處理語句結(jié)構(gòu)中,表示總是執(zhí)行的部分?! ?br>
finallize 表示是object類一個方法,在垃圾回收機制中執(zhí)行的時候會被調(diào)用被回收對象的方法。允許回收此前未回收的內(nèi)存垃圾。所有object都繼承了finalize()方法
計算機網(wǎng)絡(luò)部分。
計算機網(wǎng)絡(luò)部分還是挺容易考察的,不過考察的點不會那么深入。通常來說也就是這些問題:
TCP 有哪些狀態(tài)。
三次握手、四次揮手。為啥是三次不是兩次?
參考:
通俗大白話來理解TCP協(xié)議的三次握手和四次分手

三次握手:因為客戶端和服務(wù)端兩邊都需要確認收到對方的消息,這樣才能表示網(wǎng)絡(luò)通道是連通的??蛻舳税l(fā)起占了一次,然后雙方各自確認又占了一次,所以需要三次握手。
四次揮手:
那四次分手又是為何呢?TCP協(xié)議是一種面向連接的、可靠的、基于字節(jié)流的運輸層通信協(xié)議。TCP是全雙工模式,這就意味著,當(dāng)主機1發(fā)出FIN報文段時,只是表示主機1已經(jīng)沒有數(shù)據(jù)要發(fā)送了,主機1告訴主機2,它的數(shù)據(jù)已經(jīng)全部發(fā)送完畢了;但是,這個時候主機1還是可以接受來自主機2的數(shù)據(jù);當(dāng)主機2返回ACK報文段時,表示它已經(jīng)知道主機1沒有數(shù)據(jù)發(fā)送了,但是主機2還是可以發(fā)送數(shù)據(jù)到主機1的;當(dāng)主機2也發(fā)送了FIN報文段時,這個時候就表示主機2也沒有數(shù)據(jù)要發(fā)送了,就會告訴主機1,我也沒有數(shù)據(jù)要發(fā)送了,之后彼此就會愉快的中斷這次TCP連接。如果要正確的理解四次分手的原理,就需要了解四次分手過程中的狀態(tài)變化。
還是用打電話舉例:
1、A跟B說 我要掛斷電話了
2、B回復(fù)A 我收到你要掛斷電話的消息了
3、B跟A說 那我也要掛斷了
4、A回復(fù)B說 我確認你要掛斷了
HTTPS 和 HTTP 的區(qū)別。HTTPS 2.0,3.0?
瀏覽器輸入一個 URL,按下回車網(wǎng)絡(luò)傳輸?shù)牧鞒蹋?br>
喜歡深問一點的還會問到網(wǎng)絡(luò)架構(gòu),每層有些什么協(xié)議,F(xiàn)TP 這些相關(guān)原理,印象比較深刻的還有一個問題是:TCP 建立連接后,發(fā)包頻率是怎樣的?

Kotlin
優(yōu)點:
1、完全兼容Java
2、NULL safe
3、支持lambda表達式
4、支持擴展方法和屬性
5、優(yōu)秀的IDE支持
缺點:
1、編譯速度變慢
2、增大代碼量
3、額外的學(xué)習(xí)成本
Android 部分
Android 很廣,所以這里只是簡單說下有些什么問題。這個的話其實真的 70% 問題出自你的簡歷。
Activity 的生命周期;
Android 的 4 大啟動模式,注意 onNewIntent() 的調(diào)用;
組件化架構(gòu)思路,如何從一個老項目一步一步實現(xiàn)組件化,主要問實現(xiàn)思路,考察應(yīng)試者的架構(gòu)能力和思考能力。
這一塊內(nèi)容真的很多,你需要考慮的問題很多,哪一步做什么,順序很重要。
MVC、MCP、MVVP 的區(qū)別和各種使用場景,如何選擇適合自己的開發(fā)架構(gòu)?
Router 原理,如何實現(xiàn)組件間通信,組件化平級調(diào)用數(shù)據(jù)方式。
系統(tǒng)打包流程;
APP 啟動流程;
如何做啟動優(yōu)化?
冷啟動什么的肯定是基礎(chǔ),后續(xù)應(yīng)該還有的是懶加載,丟線程池同步處理,需要注意這里可能會有的坑是,丟線程池如何知道全部完成。
事件分發(fā)機制。
事件分發(fā)已經(jīng)不是直接讓你講了,會給你具體的場景,比如 A 嵌套 B ,B 嵌套 C,從 C 中心按下,一下滑出到 A,事件分發(fā)的過程,這里面肯定會有 ACTION_CANCEL 的相關(guān)調(diào)用時機。
如何檢測卡頓,卡頓原理是什么,怎么判斷是頁面響應(yīng)卡頓還是邏輯處理造成的卡頓?
生產(chǎn)者模式和消費者模式的區(qū)別?
單例模式雙重加鎖,為什么要這樣做。
Handler 機制原理,IdleHandler 什么時候調(diào)用。
LeakCanary 原理,為什么檢測內(nèi)存泄漏需要兩次?
BlockCanary 原理。
ViewGroup 繪制順序;
Android 有哪些存儲數(shù)據(jù)的方式。
SharedPrefrence 源碼和問題點;
講講 Android 的四大組件;
屬性動畫、補間動畫、幀動畫的區(qū)別和使用場景;
自定義 ViewGroup 如何實現(xiàn) FlowLayout?如何實現(xiàn) FlowLayout 調(diào)換順序?
自定義 View 如何實現(xiàn)打桌球效果;
自定義 View 如何實現(xiàn)拉弓效果,貝瑟爾曲線原理實現(xiàn)?
APK 瘦身是怎么做的,只用 armabi-v7a 沒有什么問題么?
APK 瘦身這個基本是 100% 被面試問到,可能是我簡歷上提到的原因。
ListView 和 RecyclerView 區(qū)別?RecyclerView 有幾層緩存,如何讓兩個 RecyclerView 共用一個緩存?
如何判斷一個 APP 在前臺還是后臺?
如何做應(yīng)用?;??全家桶原理?
講講你所做過的性能優(yōu)化。
Retrofit 在 OkHttp 上做了哪些封裝?動態(tài)代理和靜態(tài)代理的區(qū)別,是怎么實現(xiàn)的。
講講軌跡視頻的音視頻合成原理;
AIDL 相關(guān);
Binder 機制,講講 Linux 上的 IPC 通信,Binder 有什么優(yōu)勢,Android 上有哪些多進程通信機制?
RxJava 的線程切換原理。
OkHttp 和 Volloy 區(qū)別;
Glide 緩存原理,如何設(shè)計一個大圖加載框架。
LRUCache 原理;
講講咕咚項目開發(fā)中遇到的最大的一個難題和挑戰(zhàn);
這個問題基本是 95% 必問的一個問題;
說說你開發(fā)最大的優(yōu)勢點。
出現(xiàn)率同上。
算法
洗牌算法:隨機打亂一個數(shù)組的順序
java.util.Collections.shuffle(List<?> list);
如何層次遍歷樹結(jié)構(gòu)
String 轉(zhuǎn) int。
核心算法就三行代碼,不過臨界條件很多,除了判空,還需要注意負數(shù)、Integer 的最大最小值邊界等;
如何判斷一個單鏈表有環(huán)?
鏈表翻轉(zhuǎn);
快排;
100 億個單詞,找出出現(xiàn)頻率最高的單詞。要求幾種方案;
鏈表每 k 位逆序;
鏡像二叉樹;
找出一個無序數(shù)組中出現(xiàn)超過一半次數(shù)的數(shù)字;
計算二叉樹的最大深度,要求非遞歸算法。
String 方式計算加法。