精選Android中高級面試題:性能優化,JNI,設計模式

性能優化

1、圖片的三級緩存中,圖片加載到內存中,如果內存快爆了,會發生什麼?怎麼處理?

參考回答:首先我們要清楚圖片的三級緩存是如何的:

精選Android中高級面試題:性能優化,JNI,設計模式

如果內存足夠時不回收。內存不夠時就回收軟引用對象

2、內存中如果加載一張 500 * 500 的 png 高清圖片。應該是佔用多少的內存?

  • 不考慮屏幕比的話:佔用內存 = 500 * 500 * 4 = 1000000B ≈ 0.95MB
  • 考慮屏幕比的的話:佔用內存 = 寬度像素 x (inTargetDensity /inDensity) x 高度像素 x (inTargetDensity /inDensity)x 一個像素所佔的內存字節大小
  • inDensity 表示目標圖片的 dpi(放在哪個資源文件夾下),inTargetDensity 表示目標屏幕的 dpi
精選Android中高級面試題:性能優化,JNI,設計模式

3、WebView 的性能優化?

參考回答:一個加載網頁的過程中,native、網絡、後端處理、CPU 都會參與,各自都有必要的工作和依賴關係;讓他們相互並行處理而不是相互阻塞才可以讓網頁加載更快:

  • WebView 初始化慢,可以在初始化同時先請求數據,讓後端和網絡不要閒著。
  • 常用 JS 本地化及延遲加載,使用第三方瀏覽內核
  • 後端處理慢,可以讓服務器分 trunk 輸出,在後端計算的同時前端也加載網絡靜態資源。
  • 腳本執行慢,就讓腳本在最後運行,不阻塞頁面解析。
  • 同時,合理的預加載、預緩存可以讓加載速度的瓶頸更小。
  • WebView 初始化慢,就隨時初始化好一個 WebView 待用。
  • DNS 和鏈接慢,想辦法複用客戶端使用的域名和鏈接。
精選Android中高級面試題:性能優化,JNI,設計模式

推薦文章:WebView 性能、體驗分析與優化(https://tech.meituan.com/2017/06/09/webviewperf.html)

4、Bitmap 如何處理大圖,如一張 30M 的大圖,如何預防 OOM?

參考回答:避免 OOM 的問題就需要對大圖片的加載進行管理,主要通過縮放來減小圖片的內存佔用。

BitmapFactory 提供的加載圖片的四類方法(decodeFile、decodeResource、decodeStream、decodeByteArray)都支持 BitmapFactory.Options 參數,通過 inSampleSize 參數就可以很方便地對一個圖片進行採樣縮放

比如一張 10241024 的高清圖片來說。那麼它佔有的內存為 102410244,即 4MB,如果 inSampleSize 為 2,那麼採樣後的圖片佔用內存只有 512512*4, 即 1MB( 注意:根據最新的官方文檔指出,inSampleSize 的取值應該總是為 2 的指數,即 1、2、4、8 等等,如果外界輸入不足為 2 的指數,系統也會默認選擇最接近 2 的指數代替,比如 2)

綜合考慮。通過採樣率即可有效加載圖片,流程如下:

  • 將 BitmapFactory.Options 的 inJustDecodeBounds 參數設為 true 並加載圖片
  • 從 BitmapFactory.Options 中取出圖片的原始寬高信息,它們對應 outWidth 和 outHeight 參數
  • 根據採樣率的規則並結合目標 View 的所需大小計算出採樣率 inSampleSize
  • 將 BitmapFactory.Options 的 inJustDecodeBounds 參數設為 false,重新加載圖片
精選Android中高級面試題:性能優化,JNI,設計模式

推薦文章:Android 高效加載大圖、多圖解決方案,有效避免程序OOM

(https://blog.csdn.net/guolin_blog/article/details/9316683)

5、內存回收機制與 GC 算法 (各種算法的優缺點以及應用場景);GC 原理時機以及 GC 對象?

內存判定對象可回收有兩種機制:

引用計數算法:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加 1;當引用失效時,計數器值就減 1;任何時刻計數器為 0 的對象就是不可能再被使用的。然而在主流的 Java 虛擬機裡未選用引用計數算法來管理內存,主要原因是它難以解決對象之間相互循環引用的問題,所以出現了另一種對象存活判定算法。

可達性分析法:通過一系列被稱為『GCRoots』的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是不可用的。其中可作為 GC Roots 的對象:虛擬機棧中引用的對象,主要是指棧幀中的本地變量 *、本地方法棧中 Native 方法引用的對象、方法區中 類靜態屬性引用的對象、方法區中常量引用的對象

GC 回收算法有以下四種:

分代收集算法:是當前商業虛擬機都採用的一種算法,根據對象存活週期的不同,將 Java 堆劃分為新生代和老年代,並根據各個年代的特點採用最適當的收集算法。

新生代:大批對象死去,只有少量存活。使用『複製算法』,只需複製少量存活對象即可。

複製算法:把可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用盡後,把還存活著的對象『複製』到另外一塊上面,再將這一塊內存空間一次清理掉。實現簡單,運行高效。在對象存活率較高時就要進行較多的複製操作,效率將會變低

老年代:對象存活率高。使用『標記 — 清理算法』或者『標記 — 整理算法』,只需標記較少的回收對象即可。

標記 - 清除算法:首先『標記』出所有需要回收的對象,然後統一『清除』所有被標記的對象。標記和清除兩個過程的效率都不高,清除之後會產生大量不連續的內存碎片,空間碎片太多可能會導致以後在程序運行過程中需要分配較大對象時,無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。

標記 - 整理算法:首先『標記』出所有需要回收的對象,然後進行『整理』,使得存活的對象都向一端移動,最後直接清理掉端邊界以外的內存。標記整理算法會將所有的存活對象移動到一端,並對不存活對象進行處理,因此其不會產生內存碎片

推薦文章:圖解 Java 垃圾回收機制(https://blog.csdn.net/justloveyou_/article/details/71216049)

6、內存洩露和內存溢出的區別 ?AS 有什麼工具可以檢測內存洩露

  • 內存溢出 (out of memory):是指程序在申請內存時,沒有足夠的內存空間供其使用,出現 out of memory;比如申請了一個 integer,但給它存了 long 才能存下的數,那就是內存溢出。
  • 內存洩露 (memory leak):是指程序在申請內存後,無法釋放已申請的內存空間,一次內存洩露危害可以忽略,但內存洩露堆積後果很嚴重,無論多少內存,遲早會被佔光。memory leak 會最終會導致 out of memory!
  • 查找內存洩漏可以使用 Android Studio 自帶的 AndroidProfiler 工具或 MAT

7、性能優化,怎麼保證應用啟動不卡頓?黑白屏怎麼處理?

應用啟動速度:取決於你在 application 裡面時候做了什麼事情,比如你集成了很多 sdk,並且 sdk 的 init 操作都需要在主線程裡實現所以會有卡頓的感覺。在非必要的情況下可以把加載延後或則開啟子線程處理

另外,影響界面卡頓的兩大因素,分別是界面繪製和數據處理

  • 佈局優化 (使用 include,merge 標籤,複雜佈局推薦使用 ConstraintLayout 等)
  • onCreate () 中不執行耗時操作 把頁面顯示的 View 細分一下,放在 AsyncTask 裡逐步顯示,用 Handler 更好。這樣用戶的看到的就是有層次有步驟的一個個的 View 的展示,不會是先看到一個黑屏,然後一下顯示所有 View。最好做成動畫,效果更自然。
  • 利用多線程的目的就是儘可能的減少 onCreate () 和 onReume () 的時間,使得用戶能儘快看到頁面,操作頁面。
  • 減少主線程阻塞時間。
  • 提高 Adapter 和 AdapterView 的效率。

推薦文章:Android 性能優化之內存檢測、卡頓優化、耗電優化、APK 瘦身

(https://blog.csdn.net/csdn_aiyang/article/details/74989318)

黑白屏產生原因:當我們在啟動一個應用時,系統會去檢查是否已經存在這樣一個進程,如果不存在,系統的服務會先檢查 startActivity 中的 intent 的信息,然後在去創建進程,最後啟動 Acitivy,即冷啟動。而啟動出現白黑屏的問題,就是在這段時間內產生的。系統在繪製頁面加載佈局之前,首先會初始化窗口(Window),而在進行這一步操作時,系統會根據我們設置的 Theme 來指定它的 Theme 主題顏色,我們在 Style 中的設置就決定了顯示的是白屏還是黑屏。

  • windowIsTranslucent 和 windowNoTitle,將這兩個屬性都設置成 true (會有明顯的卡頓體驗,不推薦)
  • 如果啟動頁只是是一張圖片,那麼為啟動頁專一設置一個新的主題,設置主題的 android:windowBackground 屬性為啟動頁背景圖即可
  • 使用 layer-list 製作一張圖片 launcher_layer.xml,將其設置為啟動頁專一主題的背景,並將其設置為啟動頁佈局的背景。

推薦文章:Android 啟動頁解決攻略

(https://blog.csdn.net/zivensonice/article/details/51691136)

8、強引用置為 null,會不會被回收?

參考回答:不會立即釋放對象佔用的內存。如果對象的引用被置為 null,只是斷開了當前線程棧幀中對該對象的引用關係,而 垃圾收集器是運行在後臺的線程,只有當用戶線程運行到安全點 (safe point) 或者安全區域才會掃描對象引用關係,掃描到對象沒有被引用則會標記對象,這時候仍然不會立即釋放該對象內存,因為有些對象是可恢復的(在 finalize 方法中恢復引用 )。只有確定了對象無法恢復引用的時候才會清除對象內存。

9、ListView 跟 RecyclerView 的區別:

動畫區別:

  • 在 RecyclerView 中,內置有許多動畫 API,例如:notifyItemChanged (), notifyDataInserted (), notifyItemMoved () 等等;如果需要自定義動畫效果,可以通過實現(RecyclerView.ItemAnimator 類)完成自定義動畫效果,然後調用 RecyclerView.setItemAnimator ();
  • 但是 ListView 並沒有實現動畫效果,但我們可以在 Adapter 自己實現 item 的動畫效果;

刷新區別:

  • ListView 中通常刷新數據是用全局刷新 notifyDataSetChanged (),這樣一來就會非常消耗資源;本身無法實現局部刷新,但是如果要在 ListView 實現局部刷新,依然是可以實現的,當一個 item 數據刷新時,我們可以在 Adapter 中,實現一個 onItemChanged () 方法,在方法裡面獲取到這個 item 的 position(可以通過 getFirstVisiblePosition ()),然後調用 getView () 方法來刷新這個 item 的數據;
  • RecyclerView 中可以實現局部刷新,例如:notifyItemChanged ();

緩存區別:

  • RecyclerView 比 ListView 多兩級緩存,支持多個離 ItemView 緩存,支持開發者自定義緩存處理邏輯,支持所有 RecyclerView 共用同一個 RecyclerViewPool (緩存池)。
  • ListView 和 RecyclerView 緩存機制基本一致,但緩存使用不同

推薦文章:

  • 【騰訊 Bugly 乾貨分享】Android ListView 與 RecyclerView 對比淺析 — 緩存機制(https://zhuanlan.zhihu.com/p/23339185)
  • ListView 與 RecyclerView 簡單對比(https://blog.csdn.net/shu_lance/article/details/79566189)
  • Android 開發:ListView、AdapterView、RecyclerView 全面解析(https://www.jianshu.com/p/4e8e4fd13cf7)

10、ListView 的 adapter 是什麼 adapter?

精選Android中高級面試題:性能優化,JNI,設計模式

  • BaseAdapter:抽象類,實際開發中我們會繼承這個類並且重寫相關方法,用得最多的一個適配器!
  • ArrayAdapter:支持泛型操作,最簡單的一個適配器,只能展現一行文字〜
  • SimpleAdapter:同樣具有良好擴展性的一個適配器,可以自定義多種效果!
  • SimpleCursorAdapter:用於顯示簡單文本類型的 listView,一般在數據庫那裡會用到,不過有點過時,不推薦使用!

11、LinearLayout、FrameLayout、RelativeLayout 性能對比,為什麼?

  • RelativeLayout 會讓子 View 調用 2 次 onMeasure,LinearLayout 在有 weight 時,也會調用子 View 2 次 onMeasure
  • RelativeLayout 的子 View 如果高度和 RelativeLayout 不同,則會引發效率問題,當子 View 很複雜時,這個問題會更加嚴重。如果可以,儘量使用 padding 代替 margin。
  • 在不影響層級深度的情況下,使用 LinearLayout 和 FrameLayout 而不是 RelativeLayout。

JNI

1、對 JNI 是否瞭解?

參考回答:Java 的優點是跨平臺,但也因為其跨平臺的的特性導致其本地交互的能力不夠強大,一些和操作系統相關的的特性 Java 無法完成,於是 Java 提供 JNI 專門用於和本地代碼交互,通過 JNI,用戶可以調用 C、C++ 編寫的本地代碼

NDK 是 Android 所提供的一個工具集合,通過 NDK 可以在 Android 中更加方便地通過 JNI 訪問本地代碼,其優點在於:

  • 提高代碼的安全性。由於 so 庫反編譯困難,因此 NDK 提高了 Android 程序的安全性
  • 可以很方便地使用目前已有的 C/C++ 開源庫
  • 便於平臺的移植。通過 C/C++ 實現的動態庫可以很方便地在其它平臺上使用
  • 提高程序在某些特定情形下的執行效率,但是並不能明顯提升 Android 程序的性能

2、如何加載 NDK 庫 ?如何在 JNI 中註冊 Native 函數,有幾種註冊方法 ?

<code>public class JniTest{
//加載NDK庫
static{
System.loadLirary("jni-test");
}
}/<code>

註冊 JNI 函數的兩種方法:

  • 靜態方法
  • 動態註冊

推薦文章:

  • 註冊 JNI 函數的兩種方式(https://blog.csdn.net/wwj_748/article/details/52347341)
  • Android JNI 篇 - 從入門到放棄(https://www.jianshu.com/p/3dab1be3b9a4)

3、你用 JNI 來實現過什麼功能 ?怎麼實現的 ?(加密處理、影音方面、圖形圖像處理)

參考回答:推薦文章:Android JNI 篇 - ffmpeg 獲取音視頻縮略圖(https://www.jianshu.com/p/411761bd5f5b)

設計模式

1、你所知道的設計模式有哪些?

  • 創建型模式,共種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
  • 結構型模式,共種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
  • 行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

2、談談 MVC、MVP 和 MVVM,好在哪裡,不好在哪裡 ?

MVC:

  • 視圖層 (View) 對應於 xml 佈局文件和 java 代碼動態 view 部分
  • 控制層 (Controller) MVC 中 Android 的控制層是由 Activity 來承擔的,Activity 本來主要是作為初始化頁面,展示數據的操作,但是因為 XML 視圖功能太弱,所以 Activity 既要負責視圖的顯示又要加入控制邏輯,承擔的功能過多。
  • 模型層 (Model)針對業務模型,建立數據結構和相關的類,它主要負責網絡請求,數據庫處理,I/O 的操作。

總結:具有一定的分層,model 徹底解耦,controller 和 view 並沒有解耦層與層之間的交互儘量使用回調或者去使用消息機制去完成,儘量避免直接持有 controller 和 view 在 android 中無法做到徹底分離,但在代碼邏輯層面一定要分清業務邏輯被放置在 model 層,能夠更好的複用和修改增加業務。

MVP:通過引入接口 BaseView,讓相應的視圖組件如 Activity,Fragment 去實現 BaseView,實現了視圖層的獨立,通過中間層 Preseter 實現了 Model 和 View 的完全解耦。MVP 徹底解決了 MVC 中 View 和 Controller 傻傻分不清楚的問題,但是隨著業務邏輯的增加,一個頁面可能會非常複雜,UI 的改變是非常多,會有非常多的 case,這樣就會造成 View 的接口會很龐大。

MVVM:MVP 中我們說過隨著業務邏輯的增加,UI 的改變多的情況下,會有非常多的跟 UI 相關的 case,這樣就會造成 View 的接口會很龐大。而 MVVM 就解決了這個問題,通過雙向綁定的機制,實現數據和 UI 內容,只要想改其中一方,另一方都能夠及時更新的一種設計理念,這樣就省去了很多在 View 層中寫很多 case 的情況,只需要改變數據就行。

三者如何選擇?

  • 如果項目簡單,沒什麼複雜性,未來改動也不大的話,那就不要用設計模式或者架構方法,只需要將每個模塊封裝好,方便調用即可,不要為了使用設計模式或架構方法而使用。
  • 對於偏向展示型的 app,絕大多數業務邏輯都在後端,app 主要功能就是展示數據,交互等,建議使用 mvvm。
  • 對於工具類或者需要寫很多業務邏輯 app,使用 mvp 或者 mvvm 都可。

推薦文章:MVC、MVP、MVVM,我到底該怎麼選?(https://juejin.im/post/5b3a3a44f265da630e27a7e6)

3、封裝 p 層之後。如果 p 層數據過大,如何解決?

參考回答:對於 MVP 模式來說,P 層如果數據邏輯過於臃腫,建議引入 RxJava 或則 Dagger,越是複雜的邏輯,越能體現 RxJava 的優越性。

推薦文章:RxJava+OkHttp+Retrofit+Dagger2+MVP 框架 (kotlin 版本)(https://juejin.im/post/5c6e601cf265da2dc675b69e#comment)

4、是否能從 Android 中舉幾個例子說說用到了什麼設計模式 ?

  • AlertDialog、Notification 源碼中使用了 Builder(建造者)模式完成參數的初始化
  • Okhttp 內部使用了責任鏈模式來完成每個 Interceptor 攔截器的調用
  • RxJava 的觀察者模式;單例模式;GridView 的適配器模式;Intent 的原型模式
  • 日常開發的 BaseActivity 抽象工廠模式

5、裝飾模式和代理模式有哪些區別 ?

參考回答:裝飾器模式與代理模式的區別就在於:

  • 兩者都是對類的方法進行擴展,但裝飾器模式強調的是增強自身,在被裝飾之後你能夠在被增強的類上使用增強後的功能。
  • 而代理模式則強調要讓別人幫你去做一些本身與你業務沒有太多關係的職責(記錄日誌、設置緩存)代理模式是為了實現對象的控制,因為被代理的對象往往難以直接獲得或者是其內部不想暴露出來。

6、實現單例模式有幾種方法 ?懶漢式中雙層鎖的目的是什麼 ?兩次判空的目的又是什麼 ?

參考回答:單例模式實現方法有多種:餓漢,懶漢 (線程安全,線程非安全),雙重檢查 (DCL), 內部類,以及枚舉。

所謂雙層檢驗鎖(在加鎖前後對實例對象進行兩次判空的檢驗):加鎖是為了第一次對象實例化的線程同步,而鎖內還要有第二層判空是因為可能會有多個線程進入第一層 if 判斷內部,而在加鎖代碼塊外排隊等候,如果鎖內不進行第二次檢驗,仍然會出現實例化多個對象的情況。

推薦文章:單例模式的總結(https://xxxblank.github.io/2017/09/14/singleTon/)

7、用到的一些開源框架,介紹一個看過源碼的,內部實現過程。

參考回答:面試常客:Okhttp,Retrofit,Glide,RxJava,GreenDao,Dagger 等。

推薦文章:

Android OkHttp 源碼解析入門教程(一)(https://juejin.im/post/5c46822c6fb9a049ea394510)

Android OkHttp 源碼解析入門教程(二)(https://juejin.im/post/5c4682d2f265da6130752a1d)

8、Fragment 如果在 Adapter 中使用應該如何解耦?

參考回答:接口回調和廣播

最後

今天關於面試的分享就到這裡,還是那句話,有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。

最後在這裡小編分享一份自己收錄整理上述技術體系圖相關的幾十套

騰訊、頭條、阿里、美團等公司19年的面試題,把技術點整理成了視頻和PDF(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由於篇幅有限,這裡以圖片的形式給大家展示一部分。

還有 高級架構技術進階腦圖、Android開發面試專題資料,高級進階架構資料 幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習。

【Android核心高級技術PDF文檔,BAT大廠面試真題解析】

精選Android中高級面試題:性能優化,JNI,設計模式

【算法合集】

精選Android中高級面試題:性能優化,JNI,設計模式

【延伸Android必備知識點】

精選Android中高級面試題:性能優化,JNI,設計模式

【Android部分高級架構視頻學習資源】

Android精講視頻領取學習後更加是如虎添翼!進軍BATJ大廠等(備戰)!現在都說互聯網寒冬,其實無非就是你上錯了車,且穿的少(技能),要是你上對車,自身技術能力夠強,公司換掉的代價大,怎麼可能會被裁掉,都是淘汰末端的業務Curd而已!現如今市場上初級程序員氾濫,這套教程針對Android開發工程師1-6年的人員、正處於瓶頸期,想要年後突破自己漲薪的,進階Android中高級、架構師對你更是如魚得水,趕快領取吧!

【Android進階學習視頻】、【全套Android面試秘籍PDF】、【Android開發核心知識點筆記】可以 私信我【安卓】免費獲取!


分享到:


相關文章: