image

前言
很多人面試之前,可能沒有在互聯(lián)網(wǎng)公司工作過或者說工作過但年頭較短,不知道互聯(lián)網(wǎng)公司技術(shù)面試都會(huì)問哪些問題? 再加上可能自己準(zhǔn)備也不充分,去面試沒幾個(gè)回合就被面試官幾個(gè)問題打蒙了,最后以慘敗收?qǐng)觥?/p>
下述是我收錄整理的Android面試題匯總,由于篇幅原因,在這只把性能優(yōu)化部分的題目列舉出來,后續(xù)還會(huì)更新其余面試題內(nèi)容,大家可以關(guān)注一下我,及時(shí)知曉我更新的知識(shí)點(diǎn),同時(shí)這份面試集錦的整理也花費(fèi)了我很多時(shí)間,有需要的朋友可以幫忙轉(zhuǎn)發(fā)分享下,點(diǎn)個(gè)贊~
性能優(yōu)化
Android的性能優(yōu)化,主要是從以下幾個(gè)方面進(jìn)行優(yōu)化的: 穩(wěn)定(內(nèi)存溢出、崩潰) 流暢(卡頓) 耗損(耗電、流量) 安裝包(APK瘦身) 影響穩(wěn)定性的原因很多,比如內(nèi)存使用不合理、代碼異常場(chǎng)景考慮不周全、代碼邏輯不合理等,都會(huì)對(duì)應(yīng)用的穩(wěn)定性造成影響。其中最常見的兩個(gè)場(chǎng)景是:Crash 和 ANR,這兩個(gè)錯(cuò)誤將會(huì)使得程序無法使用。所以做好Crash全局監(jiān)控,處理閃退同時(shí)把崩潰信息、異常信息收集記錄起來,以便后續(xù)分析;合理使用主線程處理業(yè)務(wù),不要在主線程中做耗時(shí)操作,防止ANR程序無響應(yīng)發(fā)生。
(一)穩(wěn)定——內(nèi)存優(yōu)化
(1)Memory Monitor 工具:
它是Android Studio自帶的一個(gè)內(nèi)存監(jiān)視工具,它可以很好地幫助我們進(jìn)行內(nèi)存實(shí)時(shí)分析。通過點(diǎn)擊Android Studio右下角的Memory Monitor標(biāo)簽,打開工具可以看見較淺藍(lán)色代表free的內(nèi)存,而深色的部分代表使用的內(nèi)存從內(nèi)存變換的走勢(shì)圖變換,可以判斷關(guān)于內(nèi)存的使用狀態(tài),例如當(dāng)內(nèi)存持續(xù)增高時(shí),可能發(fā)生內(nèi)存泄漏;當(dāng)內(nèi)存突然減少時(shí),可能發(fā)生GC等,如下圖所示。
(2)LeakCanary工具:
LeakCanary是Square公司基于MAT開發(fā)的一款監(jiān)控Android內(nèi)存泄漏的開源框架。其工作的原理是: 監(jiān)測(cè)機(jī)制利用了Java的WeakReference和ReferenceQueue,通過將Activity包裝到WeakReference中,被WeakReference包裝過的Activity對(duì)象如果被回收,該WeakReference引用會(huì)被放到ReferenceQueue中,通過監(jiān)測(cè)ReferenceQueue里面的內(nèi)容就能檢查到Activity是否能夠被回收(在ReferenceQueue中說明可以被回收,不存在泄漏;否則,可能存在泄漏,LeakCanary是執(zhí)行一遍GC,若還未在ReferenceQueue中,就會(huì)認(rèn)定為泄漏)。
如果Activity被認(rèn)定為泄露了,就抓取內(nèi)存dump文件(Debug.dumpHprofData);之后通過HeapAnalyzerService.runAnalysis進(jìn)行分析內(nèi)存文件分析;接著通過HeapAnalyzer (checkForLeak—findLeakingReference---findLeakTrace)來進(jìn)行內(nèi)存泄漏分析。最后通過DisplayLeakService進(jìn)行內(nèi)存泄漏的展示。
(3)Android Lint 工具:
Android Lint Tool 是Android Sutido種集成的一個(gè)Android代碼提示工具,它可以給你布局、代碼提供非常強(qiáng)大的幫助。硬編碼會(huì)提示以級(jí)別警告,例如:在布局文件中寫了三層冗余的LinearLayout布局、直接在TextView中寫要顯示的文字、字體大小使用dp而不是sp為單位,就會(huì)在編輯器右邊看到提示。
(二)流暢——卡頓優(yōu)化
卡頓的場(chǎng)景通常是發(fā)生在用戶交互體驗(yàn)最直接的方面。影響卡頓的兩大因素,分別是界面繪制和數(shù)據(jù)處理。
界面繪制:主要原因是繪制的層級(jí)深、頁面復(fù)雜、刷新不合理,由于這些原因?qū)е驴D的場(chǎng)景更多出現(xiàn)在 UI 和啟動(dòng)后的初始界面以及跳轉(zhuǎn)到頁面的繪制上。
數(shù)據(jù)處理:導(dǎo)致這種卡頓場(chǎng)景的原因是數(shù)據(jù)處理量太大,一般分為三種情況,一是數(shù)據(jù)在處理 UI 線程,二是數(shù)據(jù)處理占用 CPU 高,導(dǎo)致主線程拿不到時(shí)間片,三是內(nèi)存增加導(dǎo)致 GC 頻繁,從而引起卡頓。
(1)布局優(yōu)化
在Android種系統(tǒng)對(duì)View進(jìn)行測(cè)量、布局和繪制時(shí),都是通過對(duì)View數(shù)的遍歷來進(jìn)行操作的。如果一個(gè)View數(shù)的高度太高就會(huì)嚴(yán)重影響測(cè)量、布局和繪制的速度。Google也在其API文檔中建議View高度不宜哦過10層?,F(xiàn)在版本種Google使用RelativeLayout替代LineraLayout作為默認(rèn)根布局,目的就是降低LineraLayout嵌套產(chǎn)生布局樹的高度,從而提高UI渲染的效率。
布局復(fù)用,使用標(biāo)簽重用layout; 提高顯示速度,使用延遲View加載; 減少層級(jí),使用標(biāo)簽替換父級(jí)布局; 注意使用wrap_content,會(huì)增加measure計(jì)算成本; 刪除控件中無用屬性;
(2)繪制優(yōu)化
過度繪制是指在屏幕上的某個(gè)像素在同一幀的時(shí)間內(nèi)被繪制了多次。在多層次重疊的 UI 結(jié)構(gòu)中,如果不可見的 UI 也在做繪制的操作,就會(huì)導(dǎo)致某些像素區(qū)域被繪制了多次,從而浪費(fèi)了多余的 CPU 以及 GPU 資源。如何避免過度繪制?
布局上的優(yōu)化。移除 XML 中非必須的背景,移除 Window 默認(rèn)的背景、按需顯示占位背景圖片
自定義View優(yōu)化。使用 canvas.clipRect() 幫助系統(tǒng)識(shí)別那些可見的區(qū)域,只有在這個(gè)區(qū)域內(nèi)才會(huì)被繪制。
(3)啟動(dòng)優(yōu)化
應(yīng)用一般都有閃屏頁SplashActivity,優(yōu)化閃屏頁的 UI 布局,可以通過 Profile GPU Rendering 檢測(cè)丟幀情況。
(三)節(jié)省——耗電優(yōu)化
在 Android5.0 以前,關(guān)于應(yīng)用電量消耗的測(cè)試即麻煩又不準(zhǔn)確,而5.0 之后Google專門引入了一個(gè)獲取設(shè)備上電量消耗信息的API—— Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系統(tǒng)電量分析工具,直觀地展示出手機(jī)的電量消耗過程,通過輸入電量分析文件,顯示消耗情況。
最后提供一些可供參考耗電優(yōu)化的方法:
(1)計(jì)算優(yōu)化。算法、for循環(huán)優(yōu)化、Switch..case替代if..else、避開浮點(diǎn)運(yùn)算。
浮點(diǎn)運(yùn)算:計(jì)算機(jī)里整數(shù)和小數(shù)形式就是按普通格式進(jìn)行存儲(chǔ),例如1024、3.1415926等等,這個(gè)沒什么特點(diǎn),但是這樣的數(shù)精度不高,表達(dá)也不夠全面,為了能夠有一種數(shù)的通用表示法,就發(fā)明了浮點(diǎn)數(shù)。浮點(diǎn)數(shù)的表示形式有點(diǎn)像科學(xué)計(jì)數(shù)法(.*****×10),它的表示形式是0.*****×10,在計(jì)算機(jī)中的形式為 .***** e ±**),其中前面的星號(hào)代表定點(diǎn)小數(shù),也就是整數(shù)部分為0的純小數(shù),后面的指數(shù)部分是定點(diǎn)整數(shù)。利用這樣的形式就能表示出任意一個(gè)整數(shù)和小數(shù),例如1024就能表示成0.1024×10^4,也就是 .1024e+004,3.1415926就能表示成0.31415926×10^1,也就是 .31415926e+001,這就是浮點(diǎn)數(shù)。浮點(diǎn)數(shù)進(jìn)行的運(yùn)算就是浮點(diǎn)運(yùn)算。浮點(diǎn)運(yùn)算比常規(guī)運(yùn)算更復(fù)雜,因此計(jì)算機(jī)進(jìn)行浮點(diǎn)運(yùn)算速度要比進(jìn)行常規(guī)運(yùn)算慢得多。
(2)避免 Wake Lock 使用不當(dāng)。
Wake Lock是一種鎖的機(jī)制,主要是相對(duì)系統(tǒng)的休眠而言的,,只要有人拿著這個(gè)鎖,系統(tǒng)就無法進(jìn)入休眠意思就是我的程序給CPU加了這個(gè)鎖那系統(tǒng)就不會(huì)休眠了,這樣做的目的是為了全力配合我們程序的運(yùn)行。有的情況如果不這么做就會(huì)出現(xiàn)一些問題,比如微信等及時(shí)通訊的心跳包會(huì)在熄屏不久后停止網(wǎng)絡(luò)訪問等問題。所以微信里面是有大量使用到了Wake_Lock鎖。系統(tǒng)為了節(jié)省電量,CPU在沒有任務(wù)忙的時(shí)候就會(huì)自動(dòng)進(jìn)入休眠。有任務(wù)需要喚醒CPU高效執(zhí)行的時(shí)候,就會(huì)給CPU加Wake_Lock鎖。大家經(jīng)常犯的錯(cuò)誤,我們很容易去喚醒CPU來工作,但是很容易忘記釋放Wake_Lock。
(3)使用 Job Scheduler 管理后臺(tái)任務(wù)。
在Android 5.0 API 21 中,google提供了一個(gè)叫做JobScheduler API的組件,來處理當(dāng)某個(gè)時(shí)間點(diǎn)或者當(dāng)滿足某個(gè)特定的條件時(shí)執(zhí)行一個(gè)任務(wù)的場(chǎng)景,例如當(dāng)用戶在夜間休息時(shí)或設(shè)備接通電源適配器連接WiFi啟動(dòng)下載更新的任務(wù)。這樣可以在減少資源消耗的同時(shí)提升應(yīng)用的效率。
(四)安裝包——APK瘦身
(1)安裝包的組成結(jié)構(gòu)
assets文件夾。存放一些配置文件、資源文件,assets不會(huì)自動(dòng)生成對(duì)應(yīng)的 ID,而是通過 AssetManager 類的接口獲取。
res。res 是 resource 的縮寫,這個(gè)目錄存放資源文件,會(huì)自動(dòng)生成對(duì)應(yīng)的 ID 并映射到 .R 文件中,訪問直接使用資源 ID。
META-INF。保存應(yīng)用的簽名信息,簽名信息可以驗(yàn)證 APK 文件的完整性。
AndroidManifest.xml。這個(gè)文件用來描述 Android 應(yīng)用的配置信息,一些組件的注冊(cè)信息、可使用權(quán)限等。
classes.dex。Dalvik 字節(jié)碼程序,讓 Dalvik 虛擬機(jī)可執(zhí)行,一般情況下,Android 應(yīng)用在打包時(shí)通過 Android SDK 中的 dx 工具將 Java 字節(jié)碼轉(zhuǎn)換為 Dalvik 字節(jié)碼。
resources.arsc。記錄著資源文件和資源 ID 之間的映射關(guān)系,用來根據(jù)資源 ID 尋找資源。
(2)減少安裝包大小
代碼混淆。使用IDE 自帶的 proGuard 代碼混淆器工具 ,它包括壓縮、優(yōu)化、混淆等功能。 資源優(yōu)化。比如使用 Android Lint 刪除冗余資源,資源文件最少化等。 圖片優(yōu)化。比如利用 PNG優(yōu)化工具 對(duì)圖片做壓縮處理。推薦目前最先進(jìn)的壓縮工具Googlek開源庫zopfli。如果應(yīng)用在0版本以上,推薦使用 WebP圖片格式。 避免重復(fù)或無用功能的第三方庫。例如,百度地圖接入基礎(chǔ)地圖即可、訊飛語音無需接入離線、圖片庫Glide\Picasso等。 插件化開發(fā)。比如功能模塊放在服務(wù)器上,按需下載,可以減少安裝包大小。 可以使用微信開源資源文件混淆工具——AndResGuard。一般可以壓縮apk的1M左右大。
冷啟動(dòng)與熱啟動(dòng)
冷啟動(dòng)在啟動(dòng)應(yīng)用時(shí),系統(tǒng)中沒有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用;
熱啟動(dòng) 在啟動(dòng)應(yīng)用時(shí),系統(tǒng)中已有該應(yīng)用的進(jìn)程(例:按back鍵、home鍵,應(yīng)用雖然會(huì)退出,但是該應(yīng)用的進(jìn)程還是保留在后臺(tái));
區(qū)別 冷啟動(dòng):系統(tǒng)沒有該應(yīng)用的進(jìn)程,需要?jiǎng)?chuàng)建一個(gè)新的進(jìn)程分配給應(yīng)用,所以會(huì)先創(chuàng)建和初始化Application類,再創(chuàng)建和初始化MainActivity類(包括一系列的測(cè)量、布局、繪制),最后顯示在界面上。 熱啟動(dòng): 從已有的進(jìn)程中來啟動(dòng),不會(huì)創(chuàng)建和初始化Application類,直接創(chuàng)建和初始化MainActivity類(包括一系列的測(cè)量、布局、繪制),最后顯示在界面上。
冷啟動(dòng)流程 Zygote進(jìn)程中fork創(chuàng)建出一個(gè)新的進(jìn)程; 創(chuàng)建和初始化Application類、創(chuàng)建MainActivity; inflate布局、當(dāng)onCreate/onStart/onResume方法都走完; contentView的measure/layout/draw顯示在界面上。
冷啟動(dòng)優(yōu)化 減少在Application和第一個(gè)Activity的onCreate()方法的工作量; 不要讓Application參與業(yè)務(wù)的操作; 不要在Application進(jìn)行耗時(shí)操作; 不要以靜態(tài)變量的方式在Application中保存數(shù)據(jù); 減少布局的復(fù)雜性和深度;
最后
給大家分享一份移動(dòng)架構(gòu)大綱,包含了移動(dòng)架構(gòu)師需要掌握的所有的技術(shù)體系,大家可以對(duì)比一下自己不足或者欠缺的地方有方向的去學(xué)習(xí)提升;
需要高清架構(gòu)圖以及圖中視頻資料和文章項(xiàng)目源碼的可以加入我的技術(shù)交流群:825106898私聊群主小姐姐免費(fèi)獲取
