Android 相關(guān)
1.關(guān)于Android 特有的數(shù)據(jù)結(jié)構(gòu)
面試過(guò)程中很多人不會(huì)直接問你知道ArrayMap 和SpareArray 嗎,而是問你android 特有的數(shù)據(jù)結(jié)構(gòu),只不過(guò)是換了一個(gè)說(shuō)法說(shuō)道這里我先和大家說(shuō)一下一個(gè)關(guān)于問到數(shù)據(jù)結(jié)構(gòu) 比如 hashmap arraymap sparearray 之類的問題,如果想要條理清晰的說(shuō)出來(lái),最好的突破方式就是先從他自身的數(shù)據(jù)結(jié)構(gòu)開始,他自身的數(shù)據(jù)結(jié)構(gòu)能決定大部分他自身的優(yōu)缺點(diǎn),只要將這些由數(shù)據(jù)結(jié)構(gòu)決定的問題說(shuō)明出來(lái),再說(shuō)一下特別的地方,基本上就可以了,
,我先來(lái)說(shuō)一下SpareArray,先從他自身的數(shù)據(jù)結(jié)構(gòu)開始的,SpareArray 是兩個(gè)數(shù)組形式的結(jié)構(gòu), key 數(shù)組存放int 類型的值,value 數(shù)組存放的是一個(gè)object類型的值,他是有序的,排列順序是根據(jù)key的大小從小至大排列的,在查找key的過(guò)程是使用的二分法來(lái)查找的,在做刪除操作的時(shí)候?qū)alue 置位空狀態(tài),并不會(huì)重新排列數(shù)據(jù), 這樣做的好處是在后續(xù)插入時(shí)在做排序比較節(jié)省時(shí)間在發(fā)現(xiàn)空節(jié)點(diǎn)只需要調(diào)整一部分結(jié)構(gòu)就可以了,如果發(fā)現(xiàn)沒有空余的節(jié)點(diǎn)則會(huì)執(zhí)行copy方法,再將新的數(shù)據(jù)插入進(jìn)去
.優(yōu)缺點(diǎn)
1.節(jié)省內(nèi)存 ...兩個(gè)有序數(shù)據(jù)的內(nèi)存空間相較于map的鏈表結(jié)構(gòu)內(nèi)從空間還是相對(duì)來(lái)說(shuō)是小的,鏈表的內(nèi)存是不連續(xù)的,這就導(dǎo)致他實(shí)際占用的空間超出他承載的控件,
2 數(shù)據(jù)有序
3.查找速度相較于hashmap來(lái)說(shuō)比較慢,由于使用二分法,位置能可會(huì)查找多次,而hashmap 則是通過(guò)hashcode 一次計(jì)算成功的
4.每次添加數(shù)據(jù)如果沒有空位,則需要copy數(shù)組,消耗性能
從上面優(yōu)缺點(diǎn)分析,如果在使用過(guò)程中數(shù)據(jù)如果對(duì)排序沒有過(guò)多的要求,那么使用sparearray 并沒有什么優(yōu)勢(shì),但是現(xiàn)在很多app都有內(nèi)存方面的劣勢(shì),以時(shí)間換空間就看自身來(lái)衡量
2. 關(guān)于app 優(yōu)化
1.內(nèi)存優(yōu)化
其實(shí)這個(gè)問題是一個(gè)比較開闊的問題,可以回答的方面就比較多了,大致可以分為幾個(gè)方面,
1.比如說(shuō)數(shù)據(jù)結(jié)構(gòu)方面的,sparearray 相較于haspmap 來(lái)說(shuō)使用的內(nèi)存就要少一些,
2.加載圖片時(shí)使用imbitmap屬性,這個(gè)屬性使用后則不會(huì)開辟新的內(nèi)存空間,而是使用上一張圖片的內(nèi)存大小,使用場(chǎng)景就死分塊加載一張圖片,在拖動(dòng)時(shí)不需要每次都開辟新的內(nèi)存空間,
3.對(duì)于需要頻繁創(chuàng)建和回收的對(duì)象,建立數(shù)據(jù)回收和復(fù)用的緩存池,這樣做的好處是避免在短時(shí)間內(nèi)創(chuàng)建和銷毀大量的對(duì)象,造成內(nèi)存抖動(dòng),內(nèi)存抖動(dòng)過(guò)程中會(huì)
4.內(nèi)存泄露,關(guān)于內(nèi)存泄露需要注意自身的生命周期和持有他的模塊的生命周期的長(zhǎng)短,比如使用activity創(chuàng)建一個(gè)全局的單利,此時(shí)就存在activity 被 單利對(duì)象長(zhǎng)期持有,在activity 執(zhí)行ondestory后不能釋放,解決方法則是使用ApplicationContext 代替activity,handler 的內(nèi)存泄露的原理就是和這個(gè)差不多,但是解決方法則不然,一個(gè)是將handler 變成靜態(tài)內(nèi)部類,第二種解決方法是使用弱引用在handler中持有activity,這樣在內(nèi)存回收時(shí)handler中所持有的的activity 也會(huì)被回收, 查找內(nèi)存泄露的方法可以使用LeakCanary ,至于原理的話大家可以好好看一下,正題的思路還是比較清晰的,關(guān)于 activity 生命周期的監(jiān)聽 idlehandler的使用 弱引用還有弱引用隊(duì)列 gc 等等的知識(shí)點(diǎn),還是有非常大的收貨的,
2. app啟動(dòng)速度優(yōu)化
1.懶加載 在app啟動(dòng)過(guò)程中,很多人都是將第三方sdk的初始化工作直接放入了Application 的OnCreate 方法內(nèi),但是部分功能并不是在在啟動(dòng)后馬上就會(huì)使用的,而是在某些應(yīng)用場(chǎng)景下才會(huì)使用,比如定位功能,可能需要我們使用某些功能或者進(jìn)入到某些頁(yè)面后才會(huì)使用,那么如果在app啟動(dòng)時(shí)就初始化就顯得浪費(fèi)啟動(dòng)性能了,可以在本地維護(hù)一個(gè)單利模式,這樣就可以在需要的時(shí)候初始化了,
2.還有一部分功能其實(shí)也是在app啟動(dòng)過(guò)程中的意義是不大的,比如埋點(diǎn)類工具,他可能是進(jìn)入到app首頁(yè)后才會(huì)開始工作,那么我們可將它延時(shí)啟動(dòng),
3.另外一部分sdk是可以放在線程中初始化的.這樣做可以釋放主線程的資源,但是并不是啟動(dòng)線程來(lái)做一些初始化工作就一定會(huì)加快app的啟動(dòng)速度,因?yàn)閱?dòng)線程相對(duì)于一些初始化信息的負(fù)荷來(lái)說(shuō)要大不少的,如果只有很少一部分sdk的初始化工作放在了線程中的來(lái)做,帶來(lái)效果可能并沒有你想象中的那么樣,
4.當(dāng)然了 windowBackground 這個(gè)屬性還是有必要設(shè)置的,否則黑屏或者白屏帶來(lái)的體驗(yàn)簡(jiǎn)直是太差了
5.如果開啟新的進(jìn)程的話,Application 的初始化工作會(huì)多次執(zhí)行,這就導(dǎo)致浪費(fèi)資源了,所以我們需要判斷,只有app的進(jìn)程可以執(zhí)行初始化工作
6.從點(diǎn)擊圖標(biāo)直到第一個(gè)Activity顯示出來(lái)可以優(yōu)化的不僅僅是Application,activity 也是其中的一部分,這也就是我們下面要介紹的xml優(yōu)化
3.布局優(yōu)化與預(yù)防過(guò)度繪制
1.減少布局嵌套,Android 的布局在 ConstraintLayout 出現(xiàn)后,在復(fù)雜布局的加載過(guò)程里有了很大的提升,結(jié)合merge ViewStub include 一起使用效果更好
2.移出無(wú)用的背景,其實(shí)這些問題大部分都來(lái)自于設(shè)計(jì)一直在修改,就導(dǎo)致針對(duì)同一個(gè)布局可能會(huì)在不同的時(shí)間多次開發(fā),而二次開發(fā)過(guò)程中可能就會(huì)忽略一些無(wú)用的背景,比如父控件有一個(gè)白色的背景,而子view 同時(shí)也設(shè)置了
- 其實(shí)過(guò)渡繪制不僅僅發(fā)生在view的層級(jí)和重復(fù)的背景,在自定義view中同樣會(huì)遇到這樣的問題,例如在view中需要繪制兩個(gè)圖片,但是這兩個(gè)圖片有交匯的區(qū)域,如果底層的繪制完成后被頂層所覆蓋,這樣就導(dǎo)致了繪制的浪費(fèi),在canvas中關(guān)于clip有一些列的api,他可以指定區(qū)域不進(jìn)行繪制,
4.在查看View 的源碼過(guò)程中,發(fā)現(xiàn) drawable.xml 是使用xmlparse 反射稱為java 的bean ,然后在調(diào)用view 的setBackground 方法設(shè)置背景,既然他是通過(guò)反射生成的draw,我們可以通過(guò)GradientDrawable 來(lái)通過(guò)代碼來(lái)寫drawable.同樣可以達(dá)到相同的效果,而且發(fā)現(xiàn)如果draw 文件下的混亂情況可能大家都有所了解,即使命名再規(guī)范,但還是會(huì)有非常多重復(fù)的文件,使用GradientDrawable 同樣也可以解決這個(gè)痛點(diǎn),封裝一個(gè)簡(jiǎn)單的工廠模式就可以了