三、常用開發(fā)技術(shù)面試題
Android性能優(yōu)化:
1、布局優(yōu)化
? ? 布局優(yōu)化的思想就是減少布局文件的層級,這個道理很淺顯,布局文件少了,繪制事件就少了,響應(yīng)速度就會提升
? ? 1、1使用一些低耗的控件比如ViewGroup,LinearLayout,懶加載控件ViewStub等
2、繪制優(yōu)化
? ? 繪制優(yōu)化主要是指避免在view的onDraw方法中進(jìn)行大量的操作,它會直接影響界面的響應(yīng)速度
? ? 2、1避免在onDraw方法中進(jìn)行局部變量,應(yīng)為onDraw方法會頻繁創(chuàng)建,這樣會產(chǎn)生大量的臨時變量占用內(nèi)存,銷毀 這些臨時變量會頻繁的執(zhí)行g(shù)c,降低效率
? ? 2、2onDraw方法中不要執(zhí)行耗時操作,它運(yùn)行在主線程,容易造成anr
3、內(nèi)存泄漏優(yōu)化
? ? 具體詳見下面
4、響應(yīng)速度和ANR優(yōu)化
? ? 核心思想是避免在主線程中進(jìn)行耗時操作,這些主線程一般指服務(wù)、廣播onReceiver,主線程等,如果在activity中左過多操作會引起黑白屏和ANR錯誤,
5、ListView優(yōu)化
? ? 復(fù)用convertView、使convertView綁定viewHolder、翻頁加載、使用緩存
6、線程優(yōu)化
? ? 使用線程池。
Android內(nèi)存泄漏相關(guān):
什么是內(nèi)存泄漏:內(nèi)存泄漏就是應(yīng)用程序申請內(nèi)存,申請內(nèi)存的對象不會被釋放,這樣就會導(dǎo)致內(nèi)存泄漏
內(nèi)存泄漏帶來哪些問題:
1、應(yīng)用可用內(nèi)存減少,增加內(nèi)存壓力
2、會頻繁的出發(fā)GC, 降低應(yīng)用的性能
3、當(dāng)沒有可用內(nèi)存時,會導(dǎo)致OOM程序異常
內(nèi)存泄漏中的常見場景&解決方案
1、單例引起的內(nèi)存泄漏
? ? 單例的生命周期跟隨整個應(yīng)用程序,對于單例我們有這幾種優(yōu)化
? ? 1、1懶加載,用到的時候在進(jìn)行初始化
? ? 1、2避免在單例中引用activity的context上下文,這樣被引用的activity就不會釋放
? ? 1、3盡量少使用單例
2、靜態(tài)變量引起的內(nèi)存泄漏
? ? 在開發(fā)過程中,盡量不要對上下文,自定義類,自定義屬性進(jìn)行statice修飾,常量除外,因?yàn)橐坏╈o態(tài)變量應(yīng)用了上下文,那么當(dāng)前上下文坐在的activity就不會被釋放,導(dǎo)致內(nèi)存泄漏
3、屬性動畫引起的內(nèi)存泄漏
android3.0以后google提供屬性動畫,屬性動畫中有一個類循環(huán)播放的動畫,如果頁面離開,動畫不關(guān)閉就會導(dǎo)致內(nèi)存泄漏
4、handler以及內(nèi)部類造成的內(nèi)存泄漏
Handler主要用于主線程跟子線程進(jìn)行通信,Handler允許發(fā)送延遲消息,如果發(fā)送延遲消息期間關(guān)閉了activity就會造成內(nèi)訓(xùn)泄露
非靜態(tài)內(nèi)部類會持有外部類的引用,如果在耗時操作期間關(guān)閉的頁面也會導(dǎo)致內(nèi)存泄漏
解決辦法:
定義靜態(tài)內(nèi)部類、對外引用弱引用
ondestory中執(zhí)行handler.removeCallbackAndMessage(null)
內(nèi)訓(xùn)泄露工具排查
1、Android profile 是 Android Studio 提供的?代碼掃描分析工具,包括CPU真用、網(wǎng)絡(luò)請求、內(nèi)存占用等情況查看,它可以幫助我們發(fā)現(xiàn)代碼機(jī)構(gòu) / 質(zhì)量問題,
2、LeakCanary 是 Square 公司開源的「Android 和 Java 的內(nèi)存泄漏檢測庫」,Square 出品,必屬精品,功能很強(qiáng)
指紋解鎖開發(fā)
1、添加權(quán)限use_fingerprint
2、獲取當(dāng)前指紋上下文對象FingerprintManager
FingerprintManager fingerprint2 = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
3、執(zhí)行三個方法
fingerprint.isHardwareDetected(); // 判斷設(shè)備是否支持指紋解鎖
?fingerprint.hasEnrolledFingerprints(); //判斷設(shè)備是否以保存過指紋信息,至少需要保存過一個
對驗(yàn)證結(jié)果進(jìn)行處理: onAuthenticationError、 onAuthenticationSuccess、 onAuthenticationFailed
淺談安卓apk加固原理和實(shí)現(xiàn)
請例舉Android中常用布局類型,并簡述其用法以及排版效率
Android中常用布局分為傳統(tǒng)布局和新型布局
傳統(tǒng)布局(編寫XML代碼、代碼生成):
? ? ? ? ?框架布局(FrameLayout):
? ? ? ? ?線性布局(LinearLayout):
? ? ? ? ?絕對布局(AbsoluteLayout):
? ? ? ? ?相對布局(RelativeLayout):
? ? ? ? ?表格布局(TableLayout):
新型布局(可視化拖拽控件、編寫XML代碼、代碼生成):
? ? ? ? ?約束布局(ConstrainLayout):
對于嵌套多層View而言,其排版效率:LinearLayout = FrameLayout >> RelativeLayout
使用過什么圖片加載庫?Glide的源碼設(shè)計(jì)哪里很微妙?
參考回答:
圖片加載庫:Fresco、Glide、Picasso等
Glide的設(shè)計(jì)微妙在于:
Glide的生命周期綁定:可以控制圖片的加載狀態(tài)與當(dāng)前頁面的生命周期同步,使整個加載過程隨著頁面的狀態(tài)而啟動/恢復(fù),停止,銷毀
Glide的緩存設(shè)計(jì):通過(三級緩存,Lru算法,Bitmap復(fù)用)對Resource進(jìn)行緩存設(shè)計(jì)
Glide的完整加載過程:采用Engine引擎類暴露了一系列方法供Request操作
如何對APK瘦身?
一個完整APK包含以下目錄(將APK文件拖到Android Studio):
META-INF/:包含CERT.SF和CERT.RSA簽名文件以及MANIFEST.MF清單文件。
assets/:包含應(yīng)用可以使用AssetManager對象檢索的應(yīng)用資源。
res/:包含未編譯到的資源 resources.arsc。
lib/:第三方庫
classes.dex:包含以Dalvik / ART虛擬機(jī)可理解的DEX文件格式編譯的類。
AndroidManifest.xml:包含核心Android清單文件。該文件列出應(yīng)用程序的名稱,版本,訪問權(quán)限和引用的庫文件。
lib、class.dex和res占用了超過90%的空間,所以這三塊是優(yōu)化Apk大小的重點(diǎn)
減少res,壓縮圖文文件
我們通常會放置多套不同分辨率的圖片以適配不同的屏幕,在實(shí)際使用中,只保留一到兩套就足夠了(xxhdpi),可以使用webp格式圖片等
減少dex文件大小
添加資源混淆,代碼混淆在壓縮apk的同時,也提升了安全性。
減少lib文件大小
由于引用了很多第三方庫,lib文件夾占用的空間通常都很大,特別是有so庫的情況下。很多so庫會同時引入armeabi、armeabi-v7a和x86這幾種類型,這里可以只保留armeabi或armeabi-v7a的其中一個就可以了,實(shí)際上微信等主流app都是這么做的。
簡述多渠道打包及原理和常用操作?
根據(jù)不同的包標(biāo)識,配合自動化埋點(diǎn),應(yīng)用在請求網(wǎng)絡(luò)的時候攜帶渠道信息,方便后臺做運(yùn)營統(tǒng)計(jì),比如說統(tǒng)計(jì)我們的應(yīng)用在不同應(yīng)用市場的下載量等信息
這里以友盟統(tǒng)計(jì)為例
1、首先在manifest.xml文件中設(shè)置動態(tài)渠道變量:
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}"></meta-data>
2、接著在app目錄下的build.gradle中配置productFlavors,也就是配置打包的渠道:
3、最后Build菜單下執(zhí)行signed APK,輸入key路徑和密碼,選擇release,選擇渠道進(jìn)行打包即可
圖片優(yōu)化,以及圖片加載框架的使用,如Picasso、 Fresco、Glide等?
1)盡量使用小的圖片,對圖片進(jìn)行壓縮,bitmapfactory.options圖片配置類,insimplesize進(jìn)行縮放,設(shè)置圖片的編碼方式;對圖片使用軟引用,內(nèi)存不夠時即時釋圖片內(nèi)存;對圖片的復(fù)用,三級緩存的使用;
即時回收不再使用的bitmap對象;
2)Picasso,不支持gif,緩存的是Argb8888的原圖,占用內(nèi)存較大,圖片的框架使用了OkHttp緩存機(jī)制,使用Http協(xié)議緩存,也是異步加載.
3)Fresco,框架是FaceBook公司推出的,適合批量加載圖片,底層是通過三級緩存(2級內(nèi)存,1級磁盤)
加載成功后自動替換成目標(biāo)圖片
4)glide,Google公司14年推出來的,可以加載GIF圖,也可以根據(jù)指定圖片清晰度,底層的原理:為Bitmap維護(hù)一個對象池,對象池的目的是通過減少對象的分配,以重用來提高性能.對象池也可以幫助提高滾動的性能。API簡潔易調(diào)用
如何對 Android 應(yīng)用進(jìn)行性能分析
如果不考慮使用其他第三方性能分析工具的話,我們可以直接使用 ddms 中的工具,其實(shí) ddms 工具已經(jīng)非常的強(qiáng)大了。ddms 中有 traceview、heap、allocation tracker 等工具都可以幫助我們分析應(yīng)用的方法執(zhí)行時間效率和內(nèi)存使用情況。
Traceview 是 Android 平臺特有的數(shù)據(jù)采集和分析工具,它主要用于分析 Android 中應(yīng)用程序的 hotspot(瓶頸)。Traceview 本身只是一個數(shù)據(jù)分析工具,而數(shù)據(jù)的采集則需要使用 AndroidSDK 中的 Debug 類或者利用 DDMS 工具。
heap 工具可以幫助我們檢查代碼中是否存在會造成內(nèi)存泄漏的地方。
allocation tracker 是內(nèi)存分配跟蹤工具
自定義View相關(guān)方法
自定義控件的實(shí)現(xiàn)有三種方式,分別是:組合控件、自繪控件和繼承控件。
1、自定義屬性的聲明和獲取
????????分析需要的自定義屬性
????????在res/values/attrs.xml定義聲明
????????在layout文件中進(jìn)行使用
????????在View的構(gòu)造方法中進(jìn)行獲取
2、測量onMeasure、布局onLayout(ViewGroup)、繪制onDraw
3、onTouchEvent、onInterceptTouchEvent(ViewGroup)
4、狀態(tài)的恢復(fù)與保存
優(yōu)化自定義 View
1、對于頻繁調(diào)用的方法,盡量減少不必要的代碼,比如onDraw方法,它運(yùn)行在UI上,使用不當(dāng)不僅會導(dǎo)致內(nèi)存緊張,還會導(dǎo)致UI卡頓
2、layout:我們都知道調(diào)用requestLayout,他會遍歷整個view層級來計(jì)算當(dāng)前view得大小,因此要較少調(diào)用次數(shù)
3、UI盡量扁平化,不要過于復(fù)雜,如果很復(fù)雜建議使用viewGroup
TCP的3次握手和四次揮手
三次握手是指,客戶端與服務(wù)端需要發(fā)送三次包
1、客戶端向服務(wù)端發(fā)送請求連接, 等待回應(yīng)
2、服務(wù)器接收到請求,并向客戶端發(fā)送相應(yīng)
3、客戶端得到服務(wù)器發(fā)送請求的相應(yīng)后,向服務(wù)器發(fā)送數(shù)據(jù)包
TCP與UDP的區(qū)別?
TCP UDP
是否連接 面向連接 面向非連接
傳輸可靠性 可靠 不可靠
應(yīng)用場合 傳輸大量數(shù)據(jù) 少量數(shù)據(jù)
速度 慢 快
HTTP與HTTPS的區(qū)別以及如何實(shí)現(xiàn)安全性
HTTP 是明文連接不安全,HTTPS是加密連接,ssl加密安全
HTTPS需要申請證書,http不需要
HTTP 速度快,HTTPS速度慢
請解釋安卓為啥要加簽名機(jī)制??談?wù)勀銓Π沧亢灻睦斫?
Android的簽名機(jī)制包含有消息摘要、數(shù)字簽名和數(shù)字證書
消息摘要:在消息數(shù)據(jù)上,執(zhí)行一個單向的 Hash 函數(shù),生成一個固定長度的Hash值
數(shù)字簽名:一種以電子形式存儲消息簽名的方法,一個完整的數(shù)字簽名方案應(yīng)該由兩部分組成:簽名算法和驗(yàn)證算法
數(shù)字證書:一個經(jīng)證書授權(quán)(Certificate Authentication)中心數(shù)字簽名的包含公鑰擁有者信息以及公鑰的文件
(三)數(shù)據(jù)庫
sqlite升級,增加字段的語句
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
升級一定要newVersion+1,否則不會走onUpgrade方法
增加字段:alter table [表名] add column [字段id] [字段類型]
(四)算法
GC算法(各種算法的優(yōu)缺點(diǎn)以及應(yīng)用場景)
1、引用計(jì)數(shù)法
? ? ? ? 每個對象頭部都會有一個counter,對象被引用一次計(jì)數(shù)器就會+1,不會引用就會-1,為0就會被gc等待回收
? ? ? ? 由循環(huán)引用的問題
2、可達(dá)性算法
? ? ? ? 以當(dāng)前節(jié)點(diǎn)為根節(jié)點(diǎn),向上搜索,如果找到父節(jié)點(diǎn)則被引用,沒有就沒有被引用,解決循環(huán)引用問題
一張Bitmap所占內(nèi)存以及內(nèi)存占用的計(jì)算
getByteCount()
public final int getByteCount() { return getRowBytes() * getHeight();}?
(五)插件化、模塊化、組件化、熱修復(fù)、增量更新、Gradle
對熱修復(fù)(熱更新)和插件化的理解
熱更新流程:
1、線上檢測驗(yàn)證的bug
2、拉出bugfix分支并在分支上修復(fù)問題
3、jenkins構(gòu)建和補(bǔ)丁生成
4、app通過推送或者拉取的方法獲取補(bǔ)丁
5、將bugfix代碼同步到主干目錄上
熱更新原理:
1、Android類加載機(jī)制
? ? ? ? PathClassLoader:主要加載系統(tǒng)的類
? ? ? ? DexClassLoader:主要加載Dex文件,jar、apk包等
2、熱修復(fù)機(jī)制
? ? ? ? 1、dexElements:放新文件和舊文件的集合
? ? ? ? 2、ClassLoader會遍歷dexElements數(shù)組
描述:在ClassLoader中創(chuàng)建一個dexElements文件的數(shù)組,根據(jù)線上的類文件,把線上的類文件打包成dex文件放到dexElements數(shù)組的最前面,ClassLoader會優(yōu)先加載最前面的dex文件,這樣就完成了新文件替換舊文件的機(jī)制
插件化原理分析
1、插件化的來源:
? ? ? ? 我們都知道app在開發(fā)維護(hù)過程中隨著版本迭代,代碼會越來越多,功能也會越來越多
? ? ? ? 銀行業(yè)務(wù)眾多,一個團(tuán)隊(duì)開發(fā)至少十幾個人,每個人都有負(fù)責(zé)一個模塊的時候,如果某個模塊更新,那么整個app? ?就會隨著更新,浪費(fèi)時間、人力。因此面對這種情況,插件化能很好的解決問提
插件化是指將 APK 分為宿主和插件的部分。把需要實(shí)現(xiàn)的模塊或功能當(dāng)做一個獨(dú)立的提取出來,在 APP 運(yùn)行時,我們可以動態(tài)的載入或者替換插件部分,減少宿主的規(guī)模
宿主: 就是當(dāng)前運(yùn)行的APP。
插件: 相對于插件化技術(shù)來說,就是要加載運(yùn)行的apk類文件。
2、插件化所要解決的問題:
? ? ? ? 2.1動態(tài)加載apk:
? ? ? ? ? ? PathClassLoader:主要加載系統(tǒng)類文件
????????????DexClassLoader主要動態(tài)加載dex文件常用于熱修復(fù)機(jī)制
所謂的動態(tài)加載apk主要是通過DexClassloader加載dex類文件來實(shí)現(xiàn),并通過反射來動態(tài)的獲取dex文件的方法、屬性和類文件信息
? ? ? ? 2.2資源加載:
? ? ? ? 一個apk訪問另一個apk資源的時候,只能通過反射來訪問被訪問apk資源,通過assestManager
? ? ? ? 2.3代碼加載:
? ? ? ? 通過反射生命周期來實(shí)現(xiàn)
模塊化實(shí)現(xiàn)(好處,原因)
定義:模塊化是一種處理復(fù)雜系統(tǒng)分解為更好的可管理模塊的方式
每個團(tuán)隊(duì)負(fù)責(zé)不同的模塊,提升開發(fā),測試效率
每個模塊實(shí)際上也是一個完整的項(xiàng)目,可以進(jìn)行單獨(dú)編譯,調(diào)試
模塊功能比較單一,可在多個項(xiàng)目中使用?
項(xiàng)目組件化的理解
引入組件化的原因:項(xiàng)目隨著需求的增加規(guī)模變得越來越大,規(guī)模的增大導(dǎo)致了各種業(yè)務(wù)錯中復(fù)雜的交織在一起, 每個業(yè)務(wù)模塊之間,代碼沒有約束,帶來了代碼邊界的模糊,代碼沖突時有發(fā)生, 更改一個小問題可能引起一些新的問題, 牽一發(fā)而動全身,增加一個新需求,需要熟悉相關(guān)的代碼邏輯,增加開發(fā)時間
避免重復(fù)造輪子,可以節(jié)省開發(fā)和維護(hù)的成本。
可以通過組件和模塊為業(yè)務(wù)基準(zhǔn)合理地安排人力,提高開發(fā)效率。
不同的項(xiàng)目可以共用一個組件或模塊,確保整體技術(shù)方案的統(tǒng)一性。
為未來插件化共用同一套底層模型做準(zhǔn)備。
組件化開發(fā)流程就是把一個功能完整的App或模塊拆分成多個子模塊(Module),每個子模塊可以獨(dú)立編譯運(yùn)行,也可以任意組合成另一個新的 App或模塊,每個模塊即不相互依賴但又可以相互交互,但是最終發(fā)布的時候是將這些組件合并統(tǒng)一成一個apk,遇到某些特殊情況甚至可以升級或者降級
舉個簡單的模型例子

App是主application,ModuleA和ModuleB是兩個業(yè)務(wù)模塊(相對獨(dú)立,互不影響),Library是基礎(chǔ)模塊,包含所有模塊需要的依賴庫,以及一些工具類:如網(wǎng)絡(luò)訪問、時間工具等
描述清點(diǎn)擊 Android Studio 的 build 按鈕后發(fā)生了什么(apk打包流程)
流程概述:
1、打包資源文件,生成R.java文件
2、處理aidl文件,生成相應(yīng)java 文件
3、編譯工程源代碼,生成相應(yīng)class 文件
4、轉(zhuǎn)換所有class文件,生成classes.dex文件
5、打包生成apk6、對apk文件進(jìn)行簽名7、對簽名后的apk文件進(jìn)行對其處理
在 AndroidStudio 工程點(diǎn)擊 Run 按鈕, 實(shí)際上做了什么操作呢?
1、檢查項(xiàng)目和讀取基本配置
2、Gradle Build
3、Apk Install & LaunchActivity
(六)架構(gòu)設(shè)計(jì)和設(shè)計(jì)模式
談?wù)勀銓ndroid設(shè)計(jì)模式的理解
什么是設(shè)計(jì)模式
????????設(shè)計(jì)模式是一種解決方案,它代表了實(shí)現(xiàn)代碼的最佳實(shí)踐
設(shè)計(jì)模式的作用
? ??????? 設(shè)計(jì)模式就是用來解決軟件設(shè)計(jì)中應(yīng)對變化,提高軟件復(fù)用性。設(shè)計(jì)模式使軟件更加可維護(hù)、可拓展、更加穩(wěn)定、可復(fù)用性強(qiáng)
常見的設(shè)計(jì)模式
? ? ? ? 單例、觀察者、工廠、狀態(tài)機(jī)模式
MVC MVP MVVM原理和區(qū)別
用到的一些開源框架,介紹一個看過源碼的,內(nèi)部實(shí)現(xiàn)過程。
從0設(shè)計(jì)一款A(yù)pp整體架構(gòu),如何去做?
1、需求分析,確定功能
2、根據(jù)功能,確定模塊化開發(fā)或者組件化開發(fā)
3、根據(jù)業(yè)務(wù)模塊確定架構(gòu)MVC、MVP、MVVM
4、根據(jù)架構(gòu)模式進(jìn)行編碼、優(yōu)化
Binder機(jī)制及底層實(shí)現(xiàn)
1、為什么要使用Binder
? ? ? ? android使用linux內(nèi)核,它里面有非常多的進(jìn)程通信機(jī)制
? ? ? ? 性能,手機(jī)注重性能,
? ? ? ? 安全,支持通信雙方進(jìn)行身份校驗(yàn)
2、Binder的通信模型
(七)性能優(yōu)化
如何對Android 應(yīng)用進(jìn)行性能分析以及優(yōu)化?
性能分析工具:traceview、heap、allocation tracker
traceview:數(shù)據(jù)采集和分析工具
heap:工具可以幫助我們檢查代碼中是否存在會造成內(nèi)存泄漏的地方
用IDE如何分析內(nèi)存泄漏?
Android Profiler內(nèi)存分析工具
通過Profiler可以查看CPU、Memory和Network的調(diào)用情況。
Java多線程引發(fā)的性能問題,怎么解決?
java中多線程除了能解決耗時操作,但是線程的開銷是非常占用資源的。
1、線程的生命周期開銷高,線程從創(chuàng)建到銷毀時間不固定
2、線程是一種有線cpu資源,過多的線程會占用更多的cpu資源
3、線程超過jvm內(nèi)存限制會引起OOM問題
解決辦法:
1、使用線程池,更好的利用資源
線程池有核心線程數(shù)、緩沖線程數(shù)、最大線程數(shù),可根據(jù)線程的輕重緩急來合理分配資源
啟動頁白屏及黑屏解決?
首先我們分析一下為什么會有黑白屏問題:
1、啟動app,系統(tǒng)進(jìn)程會創(chuàng)建一個新的進(jìn)程啟動當(dāng)前app,當(dāng)然這個啟動是有時間的。這個時間段界面呈現(xiàn)假死狀態(tài),android為我們解決的辦法是在mainfest配置文件中設(shè)置不同的主題來展示黑屏或者白屏。也就是預(yù)覽窗口
2、 針對這個問題,我的解決方案是,
????可以在drawable文件夾下定義一個啟動xml文件
? ? 添加一個主題style,設(shè)置名字為SplashAppTheme ,給android:windowBackground 指定xml文件
? ? 在清單文件中給啟動頁activity的Theme單獨(dú)設(shè)置我們剛才添加的主題
<style name="SplashAppTheme" parent="android:Theme">
????????<item name="android:windowNoTitle">true</item>
????????<item name="android:windowFullscreen">true</item>
????????<item name="android:windowBackground">@drawable/layer_splash</item>
????</style>
怎么保證應(yīng)用啟動不卡頓?
應(yīng)用卡頓的原因是界面繪制頻繁,主線程做了過多的耗時操作
如何保持應(yīng)用的穩(wěn)定性
1、用戶體驗(yàn)、流暢的運(yùn)行app
2、軟件崩潰,最主要的OOM問題
3、性能分析
RecyclerView和ListView的性能對比
ListView 回收機(jī)制基于RecyclerBin(mActivitysViews、mSpacpViews)
RecyclerView 回收機(jī)制Recycler(mCachesViews、Viewpool)
ListView的優(yōu)化
1、復(fù)用convertView
2、使convertView綁定View Holder
3、翻頁加載
4、使用緩存
Bitmap如何處理大圖,如一張30M的大圖,如何預(yù)防OOM
Bitmap加載一張30M的大圖為了避免引起OOM,需要使用采樣率進(jìn)行展示(根據(jù)屏幕不影響分辨率情況下展示),流程
1、將BitmapFactory.Options的inJustDecodeBounds設(shè)為true并加載圖片
2、從BitmapFactory.Options獲取圖片的outWidth、outHeight
3、根據(jù)采樣率的規(guī)則結(jié)合目標(biāo)View的大小和outWidth和outHeight計(jì)算出采樣率inSampleSize
4、將BitmapFactory.Options的inJustDecodeBounds設(shè)為false重新加載圖片
java中的四種引用的區(qū)別以及使用場景
強(qiáng)應(yīng)用:當(dāng)前對象如果是強(qiáng)引用,它會一直存在內(nèi)存中,生命周期跟隨程序生命周期,寧愿拋出OOM也不會被回收
軟引用:當(dāng)前對象如果是軟引用,內(nèi)存充足時不會被回收,內(nèi)存不足時會優(yōu)先回收
弱引用:不管內(nèi)存充足與否,只要被GC掃描到就會被回收。
虛引用:與弱引用一樣,隨時會被回收?
(八)NDK、jni、Binder、AIDL、進(jìn)程通信有關(guān)
請介紹一下NDK
NDK是Android提供的工具集合,通過NDK,可以更方便的使用JNI訪問本地代碼。具有如下好處:
1、提高代碼的安全性,因?yàn)閟o庫反編譯困難
2、可以很方便的使用目前C/C++開源庫
3、便于平臺間的移植
4、提高程序在某些特定情況下的執(zhí)行效率
什么是NDK庫?
一些里庫的集合,比如log庫,第三方的openssl庫,主要是方便調(diào)用
jni用過嗎?
JNI是為了java調(diào)用c、c++封裝的一層接口
JNI調(diào)用本代碼開發(fā)流程:靜態(tài)注冊、動態(tài)注冊
靜態(tài)注冊
1、在java中生命native方法
2、用c、c++代碼實(shí)現(xiàn)native方法
3、編譯運(yùn)行
動態(tài)注冊
1、我們知道Java Native函數(shù)和JNI函數(shù)時一一對應(yīng)的,JNI中就有一個叫JNINativeMethod的結(jié)構(gòu)體來保存這個對應(yīng)關(guān)系,實(shí)現(xiàn)動態(tài)注冊方就需要用到這個結(jié)構(gòu)體
JNI調(diào)用java流程:
1、先通過類名找到類
2、根據(jù)方法名找到方法id
3、直接調(diào)用,如果類為非靜態(tài)類,需要先構(gòu)造類對象
類型簽名: 類:L+包名+類名
方法:(參數(shù)類型) + 返回值類型
基本類型:[ + 類型
Java如何調(diào)用c、c++語言?
Java支持跨平臺開發(fā),android為了java和本地代碼進(jìn)行交互,定義了jni,jni是java為了調(diào)用c、c++代碼封裝的一層接口
jni如何調(diào)用java層代碼?
1、根據(jù)類名找到類
2、根據(jù)方法名找到方法id
3、直接調(diào)用方法,如果類為非靜態(tài)類,需要先構(gòu)造類對象
進(jìn)程間通信的方式?
Bundle、文件共享、ContentProvider、AIDL
Binder機(jī)制
直觀的說Binder是一個類,它實(shí)現(xiàn)了IBinder接口
簡述IPC?
什么是IPC?
IPC簡稱進(jìn)程間通信,是指兩個進(jìn)程之間進(jìn)行數(shù)據(jù)交換的過程
為什么要用IPC(從多進(jìn)程通信會造成哪些方面的問題)
1、靜態(tài)成員或單例模式失效
我們都知道Android中不同進(jìn)程系統(tǒng)會分配不同的虛擬機(jī),每個虛擬機(jī)在內(nèi)存分配中都有單獨(dú)的內(nèi)存地址,不同的虛擬機(jī)訪問同一個類對象會產(chǎn)生多分副本,因此從一個進(jìn)程改變靜態(tài)變量,在另一個進(jìn)程訪問不會發(fā)生癌變
2、線程同步完全失效。內(nèi)存不同線程鎖對象也不同
3、SharedPreferences失效,它本身不支持多進(jìn)程讀寫,容易引起數(shù)據(jù)丟失
4、Application會多次創(chuàng)建
什么是AIDL?
AIDL解決了什么問題?
AIDL如何使用?
Android 上的 Inter-Process-Communication 跨進(jìn)程通信時如何工作的?
談?wù)剬Χ噙M(jìn)程開發(fā)的理解以及多進(jìn)程應(yīng)用場景
主要談?wù)刟ndroid
android中默認(rèn)情況下,同意應(yīng)用會運(yùn)行在一個進(jìn)程中,android:process可以指定不同進(jìn)程
(九)framework層、ROM定制、Ubuntu、Linux之類的問題?
談?wù)剬vm的理解
1?虛擬機(jī)并不神秘,在操作系統(tǒng)的角度看來,它只是一個普通進(jìn)程。
2?這個叫做虛擬機(jī)的進(jìn)程比較特殊,它能夠加載我們編寫的class文件。如果把JVM比作一個人,那么class文件就是我們吃的食物。
3?加載class文件的是一個叫做類加載器的子系統(tǒng)。就好比我們的嘴巴,把食物吃到肚子里。
4?虛擬機(jī)中的執(zhí)行引擎用來執(zhí)行class文件中的字節(jié)碼指令。就好比我們的腸胃,對吃進(jìn)去的食物進(jìn)行消化。
5?虛擬機(jī)在執(zhí)行過程中,要分配內(nèi)存創(chuàng)建對象。當(dāng)這些對象過時無用了,必須要自動清理這些無用的對象。清理對象回收內(nèi)存的任務(wù)由垃圾收集器負(fù)責(zé)。就好比人吃進(jìn)去的食物,在消化之后,必須把廢物排出體外,騰出空間可以在下次餓的時候吃飯并消化食物。
對Dalvik、ART虛擬機(jī)有什么了解?
JVM是java虛擬機(jī),運(yùn)行的是java字節(jié)碼,將字節(jié)碼保存在class文件,java通過節(jié)碼class文件來執(zhí)行
Dalvik是安卓虛擬機(jī),運(yùn)行的字節(jié)碼有java字節(jié)碼轉(zhuǎn)化過來,保存在dex文件中,dev通過執(zhí)行dex文件來執(zhí)行字節(jié)碼
類加載機(jī)制
負(fù)責(zé)加載java字節(jié)碼,并將字節(jié)碼轉(zhuǎn)化成.class文件的實(shí)例
談?wù)剬lassLoader(類加載器)的理解
JVM類加載機(jī)制分為五個部分:
加載:主要在內(nèi)存中生成一個類的Class對象
驗(yàn)證:確保Class中的字節(jié)流包含的信息符合虛擬機(jī)的要求
準(zhǔn)備:為方法區(qū)中的變量分配內(nèi)存控件
解析:虛擬機(jī)將常量池中的符號引用替換為直接引用的過程
初始化:真正的執(zhí)行java代碼
談?wù)剬討B(tài)加載(OSGI)的理解
定義:動態(tài)加載就是在程序運(yùn)行過程中動態(tài)的獲取類的方法、屬性、類信息
作用:通過對類的動態(tài)加載,我們只需要關(guān)注類的改變,而不需要關(guān)注實(shí)現(xiàn)動態(tài)加載相關(guān)代碼的操作
例如:反射……
內(nèi)存對象的循環(huán)引用及避免
A被B引用,B引用C,C引用A,引用計(jì)數(shù)法不會解決循環(huán)引用,會導(dǎo)致內(nèi)存泄漏,
1、可達(dá)性回收算法
2、盡量避免循環(huán)引用
內(nèi)存回收機(jī)制、GC回收策略、GC原理時機(jī)以及GC對象
1、java內(nèi)存分配:
堆:主要存放對象和數(shù)組,gc管理
棧:虛擬機(jī)棧和本地方法棧
方法區(qū):主要是類、靜態(tài)變量、常量和編譯之后的.class字節(jié)碼
2、GC回收機(jī)制(判斷是否可以回收):
? ? 引用計(jì)數(shù)法:
? ? ? ? ? ? ????????原理:通過一個計(jì)數(shù)器對對象進(jìn)行計(jì)數(shù),對象被引用時+1,引用失效時-1;當(dāng)計(jì)數(shù)為0時則說明可以被回收;
????????????????????缺點(diǎn):很難解決對象的相互循環(huán)引用問題?
? ? 可達(dá)性算法:“GC Roots”作為對象起始點(diǎn)向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的?
3、GC回收機(jī)制:(如何回收)
標(biāo)記清除算法:直接回收沒有標(biāo)記的對象,缺點(diǎn):容易產(chǎn)生碎片
標(biāo)記整理算法:將未標(biāo)記的對象移動到端最后,然后清除
復(fù)制算法:將內(nèi)存分為A、B兩塊,將A中的對象復(fù)制到B中,然后再把A中清除,缺點(diǎn):犧牲一般內(nèi)存
分代回收算法:新生代和老年代;整合了標(biāo)記整理算法和復(fù)制算法
4、GC回收機(jī)制:(執(zhí)行回收)
Scavenge GC:當(dāng)對象申請內(nèi)存失敗時出觸發(fā)
Full GC :對整個堆進(jìn)行整理
大體說清一個應(yīng)用程序安裝到手機(jī)上時發(fā)生了什么
簡述Activity啟動全部過程
1、點(diǎn)擊App圖標(biāo)后通過startActivity遠(yuǎn)程調(diào)用到AMS中,AMS中將新啟動的activity以activityrecord的結(jié)構(gòu)壓入activity棧中,并通過遠(yuǎn)程binder回調(diào)到原進(jìn)程,使得原進(jìn)程進(jìn)入pause狀態(tài),原進(jìn)程pause后通知AMS我pause了
2、此時AMS再根據(jù)棧中Activity的啟動intent中的flag是否含有new_task的標(biāo)簽判斷是否需要啟動新進(jìn)程,啟動新進(jìn)程通過startProcessXXX的函數(shù)
3、啟動新進(jìn)程后通過反射調(diào)用ActivityThread的main函數(shù),main函數(shù)中調(diào)用looper.prepar和lopper.loop啟動消息隊(duì)列循環(huán)機(jī)制。最后遠(yuǎn)程告知AMS我啟動了。AMS回調(diào)handleLauncherAcitivyt加載activity。在handlerLauncherActivity中會通過反射調(diào)用Application的onCreate和activity的onCreate以及通過handleResumeActivity中反射調(diào)用Activity的onResume
Android為每個應(yīng)用程序分配的內(nèi)存大小是多少?
起初是30M,后來google取消了這個限制,可以用過android:largeHeap="true" 來設(shè)置
進(jìn)程?;畹姆绞?/p>
1、android進(jìn)程的優(yōu)先級
前臺進(jìn)程:當(dāng)前正在與用戶操作的進(jìn)程
可見進(jìn)程:沒有其他組件,但內(nèi)容可見
服務(wù)進(jìn)程:執(zhí)行與前臺進(jìn)程相關(guān)的操作
后臺進(jìn)程:用來回收內(nèi)存,LRU算法
空進(jìn)程:
2、android進(jìn)程的回收策略
Low memory kill:比較復(fù)雜的評分機(jī)制,對進(jìn)程進(jìn)行打分,評分高的進(jìn)程為bad進(jìn)程,殺死并釋放內(nèi)存
OOM_ODJ:判斷進(jìn)程的優(yōu)先級,優(yōu)先級越低,low memory kill就會啟動
3、進(jìn)程?;罘桨?/p>
利用系統(tǒng)廣播拉活:通過廣播監(jiān)聽被殺死就立即拉活
利用startForground:調(diào)用startForground開啟一個前臺進(jìn)程,降低oom_odj值,提升進(jìn)程優(yōu)先級
目前比較有效的方法有JobScheduler :
如何保證一個后臺服務(wù)不被殺死?(相同問題:如何保證service在后臺不被kill?)比較省電的方式是什么?
1、通過android:priority = 1000提升服務(wù)的優(yōu)先級
2、在onDestroy中通過通知來重啟服務(wù)
3、通過startForground將服務(wù)至于前臺:開發(fā)者在后臺創(chuàng)建job,當(dāng)某些條件被允許時,后臺進(jìn)程開始工作。
隨著系統(tǒng)的更新,很多進(jìn)程?;罘桨甘?/p>
App中喚醒其他進(jìn)程的實(shí)現(xiàn)方式
1、自定義啟動協(xié)議:<data android:scheme="wapchief" />
2、Activity中獲取其它進(jìn)程傳遞的Data數(shù)據(jù)
3、正則匹配要跳轉(zhuǎn)的界面
4、在調(diào)用方APP使用指定協(xié)議跳轉(zhuǎn)
介紹你做過的哪些項(xiàng)目
都使用過哪些框架、平臺?
都使用過哪些自定義控件?
研究比較深入的領(lǐng)域有哪些?
最近都讀哪些書?
android開發(fā)藝術(shù)探究,希望多了解一下IPC通信方式和Binder機(jī)制。以及四大組件原理
自己最擅長的技術(shù)點(diǎn),最感興趣的技術(shù)領(lǐng)域和技術(shù)點(diǎn)
項(xiàng)目中用了哪些開源庫,如何避免因?yàn)橐腴_源庫而導(dǎo)致的安全性和穩(wěn)定性問題