一般我們做引導(dǎo)頁的邏輯是:
1.先判斷是否第一次啟動(dòng)app问词,如果是础浮,則進(jìn)入功能使用導(dǎo)航(最簡(jiǎn)單的做法就是,左右滑動(dòng)切換查看沽瞭,滑動(dòng)到最后一頁點(diǎn)擊按鈕進(jìn)入首頁)迁匠。
2.如果不是,則顯示啟動(dòng)屏秕脓,2秒之后進(jìn)入首頁柒瓣。
如果有廣告怎么辦?廣告從服務(wù)器拿吠架,緩存到本地,沒網(wǎng)的時(shí)候可以顯示搂鲫,或者使用webView來顯示廣告傍药。自己寫的話用ViewPager即可: ?www.reibang.com/p/adb21180862a
但我在逛github時(shí),發(fā)現(xiàn)了一個(gè)不錯(cuò)的控件:2000+star? 使用也很方便
地址:github.com/bingoogolapple/BGABanner-Android
由于項(xiàng)目需要加載本地圖片,需要在此處:
OK 在自己手機(jī)上測(cè)試非常流暢 在蒲公英上部署完版本后我就去忙別的事了??
可是不一會(huì)項(xiàng)目經(jīng)理說在他手機(jī)上應(yīng)用打不開魂仍,直接崩潰 ?
早期在構(gòu)建項(xiàng)目時(shí)我引入了bugly拐辽,于是立刻看bugly后臺(tái),必須說騰訊出的bugly確實(shí)很好用? 報(bào)錯(cuò)一目了然 還有解決方案
問題一目了然擦酌,加載圖片時(shí)占用內(nèi)存過多直接崩潰俱诸,發(fā)生OOM了,我的手機(jī)內(nèi)存空間比較大赊舶,躲避了OOM,但內(nèi)存小一些的手機(jī)就崩潰了睁搭,其實(shí)加載網(wǎng)絡(luò)圖片也容易發(fā)生OOM赶诊,不過在此處是另外一種情況,對(duì)于此园骆,解決方式很多:
1.適當(dāng)調(diào)整圖像大小舔痪。?
我推薦使用 熊貓壓縮 tinypng.com/??
直接在網(wǎng)站上壓縮,方便快捷锌唾,圖片不失真锄码,效果顯著,可一次上傳多張圖片
2.采用合適的緩存策略。
一般用于首次加載通過網(wǎng)絡(luò)加載晌涕,獲取圖片滋捶,然后保存到內(nèi)存和 SD 卡中。
之后運(yùn)行 APP 時(shí)余黎,優(yōu)先訪問內(nèi)存中的圖片緩存炬太。
如果內(nèi)存沒有,則加載本地 SD 卡中的圖片驯耻。
具體的緩存策略可以是這樣的:內(nèi)存作為一級(jí)緩存亲族,本地作為二級(jí)緩存,網(wǎng)絡(luò)加載為最后可缚。其中霎迫,內(nèi)存使用 LruCache ,其內(nèi)部通過 LinkedhashMap 來持有外界緩存對(duì)象的強(qiáng)引用帘靡;對(duì)于本地緩存知给,使用 DiskLruCache。加載圖片的時(shí)候描姚,首先使用 LRU 方式進(jìn)行尋找涩赢,找不到指定內(nèi)容,按照三級(jí)緩存的方式轩勘,進(jìn)行本地搜索筒扒,還沒有就網(wǎng)絡(luò)加載。
代碼:www.reibang.com/p/05132e3b7320
3.采用低內(nèi)存占用量的編碼方式
比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省內(nèi)存绊寻。
1920*1200的圖片:
ARGB_8888:1920*1200*4/1024/1024=8.79MB
ARGB_4444,RGB565:1920*1200*2/1024/1024=4.39MB
但是色彩質(zhì)量會(huì)下降花墩。
4.及時(shí)回收Bitmap
一般而言,回收bitmap內(nèi)存可以用到以下代碼
if(!bitmapObject.isRecyled()) {? // Bitmap對(duì)象沒有被回收
bitmapObject.recycle();? // 釋放
System.gc();? // 提醒系統(tǒng)及時(shí)回收
}
bitmap.recycle()方法用于回收該bitmap所占用的內(nèi)存澄步,接著將bitmap置空冰蘑,最后,別忘了用System.gc()調(diào)用一下系統(tǒng)的垃圾回收器村缸。
在這里要聲明一下祠肥,bitmap可以有多個(gè)(以為著可以有多個(gè)if語句),但System.gc()最好只有一個(gè)(所以我將它寫在了if語句外)梯皿,因?yàn)镾ystem.gc()
每次調(diào)用都要將整個(gè)內(nèi)存掃描一遍仇箱,因而如果多次調(diào)用的話會(huì)影響程序運(yùn)行的速度县恕。為了程序的效率,我將它放在了所有回收語句之后工碾,
這樣已經(jīng)起到了它的效果弱睦,還節(jié)約的時(shí)間。
回收bitmap已經(jīng)知道了渊额,那么“及時(shí)”怎么理解呢况木?
根據(jù)我的實(shí)際經(jīng)驗(yàn),bitmap發(fā)揮作用的地方要么在View里旬迹,要么在Activity里(當(dāng)然肯定有其他區(qū)域火惊,但是原理都是類似的),
回收bitmap的地方最好寫在這些區(qū)域剛剛不使用bitmap了的時(shí)刻奔垦。
比如說View如果使用了bitmap,就應(yīng)該在這個(gè)View不再繪制了的時(shí)候回收屹耐,或者是在跳轉(zhuǎn)到的下一個(gè)區(qū)域的代碼中回收;
再比如說SurfaceView椿猎,就應(yīng)該在onSurfaceDestroyed這個(gè)方法中回收惶岭;
同理,如果Activity使用了bitmap,就可以在onStop或者onDestroy方法中回收......
結(jié)合以上的共同點(diǎn)犯眠,“及時(shí)回收”的原理就是在使用了bitmap的區(qū)域結(jié)束時(shí)或結(jié)束后回收按灶。
5 在manifest文件application節(jié)點(diǎn)加入android:largeHeap=“true”
設(shè)置largeHeap的確可以增加內(nèi)存的申請(qǐng)量。但不是系統(tǒng)有多少內(nèi)存就可以申請(qǐng)多少筐咧,而是由dalvik.vm.heapsize限制鸯旁。
但是作為程序員的我們應(yīng)該努力減少內(nèi)存的使用,盡量想回收和復(fù)用的方法量蕊,而不是想方設(shè)法增大內(nèi)存铺罢。當(dāng)內(nèi)存很大的時(shí)候,每次gc的時(shí)間也會(huì)長(zhǎng)一些残炮,性能會(huì)下降的韭赘。
6 使用繪制背景或者Drawable代替圖片
以上都是一些常用的解決方案,回到項(xiàng)目中我發(fā)現(xiàn)吉殃,此前為了減小apk大小辞居,在mipmap中對(duì)于引導(dǎo)圖的資源圖片,我只用了一套蛋勺。而且圖片大小我之前已經(jīng)壓縮過,每張都僅僅在200K左右鸠删,這是為什么呢抱完?
碰巧看到了這篇測(cè)試研究:關(guān)于Android中圖片大小、內(nèi)存占用與drawable文件夾關(guān)系的研究與分析 ? ?mp.weixin.qq.com/s/7I8JcjzUzDl46cfAe8yS4Q
從上面的測(cè)試結(jié)果刃泡,我們可以得出如下結(jié)論:
1.同一張圖片巧娱,放在不同目錄下碉怔,會(huì)生成不同大小的Bitmap
2.Bitmap的長(zhǎng)度和寬度越大,占用的內(nèi)存就越大
3.圖片在硬盤上占用的大小禁添,與在內(nèi)存中占用的大小完全不一樣
我們以放在drawable文件夾下面的圖片為例撮胧,加載到內(nèi)存之后,2160*3840大小的Bitmap占用的內(nèi)存為
2160 ?3840 ?4 = 3317,7600 byte = 3,2400kb = 31.640625 M
所以drawable文件夾下的App內(nèi)存占用 = 原始內(nèi)存8.31M+圖片內(nèi)存31.64M= 39.95M 老翘,與實(shí)際內(nèi)存占用39.88M存在0.1755%的誤差芹啥,在誤差范圍之內(nèi)。
先簡(jiǎn)單解釋一下上面的計(jì)算公式铺峭,長(zhǎng)*寬是圖片的像素總數(shù)墓怀,乘以4則是因?yàn)橐粋€(gè)像素占用A、R卫键、G傀履、B四個(gè)通道,每個(gè)通道占用8位莉炉,所以描述一個(gè)像素需要32位即4個(gè)字節(jié)钓账。
一個(gè)顏色通道需要8位描述,2^8=256絮宁,所以每個(gè)顏色通道就有256種狀態(tài)梆暮。如果把彩色圖轉(zhuǎn)化成灰階圖的話,也有256種狀態(tài)分割從白色到黑色之間的過渡顏色羞福。
當(dāng)然惕蹄,也并不是所有格式的圖片每個(gè)像素占用4字節(jié),這和圖片在加載時(shí)設(shè)置的Bitmap.Config有關(guān)治专,默認(rèn)的是Bitmap.Config.ARGB_8888卖陵,其他類型如下:
Bitmap.Config.ALPHA_8 此時(shí)圖片只有alpha值,沒有RGB值张峰,1個(gè)像素占用一個(gè)字節(jié)
Bitmap.Config.ARGB_4444 一個(gè)像素占用2個(gè)字節(jié)泪蔫,alpha(A)值,Red(R)值喘批,Green(G)值撩荣,Blue(B)值各占4個(gè)bites共16bites,即2個(gè)字節(jié)
Bitmap.Config.ARGB_8888 一個(gè)像素占用4個(gè)字節(jié),alpha(A)值饶深,Red(R)值餐曹,Green(G)值,Blue(B)值各占8個(gè)bites敌厘,共32bites,即4個(gè)字節(jié)台猴。這是一種高質(zhì)量的圖片格式,在電腦上普通采用。它也是Android手機(jī)上一個(gè)Bitmap的默認(rèn)格式饱狂。
Bitmap.Config.RGB_565 一個(gè)像素占用2個(gè)字節(jié)曹步,沒有alpha(A)值,即不支持透明和半透明休讳,Red(R)值占5個(gè)bites 讲婚,Green(G)值占6個(gè)bites ,Blue(B)值占5個(gè)bites,共16bites,即2個(gè)字節(jié)俊柔。對(duì)于沒有透明和半透明顏色的圖片來說筹麸,該格式的圖片能夠達(dá)到比較的呈現(xiàn)效果,相對(duì)于ARGB_8888來說也能減少一半的內(nèi)存開銷婆咸。因此它是一個(gè)不錯(cuò)的選擇竹捉。
那么為啥在硬盤上存儲(chǔ)只需要77.11k,放到內(nèi)存里面就需要30多M呢尚骄?
存放在硬盤上的圖片文件块差,會(huì)根據(jù)各自的壓縮規(guī)則進(jìn)行壓縮,比如Jpeg這種有損壓縮的圖片格式倔丈,最常使用可變字長(zhǎng)編碼的哈弗曼編碼憨闰,會(huì)使用哈弗曼樹,也就是最優(yōu)二叉樹需五,根據(jù)某些數(shù)據(jù)出現(xiàn)的頻率對(duì)數(shù)據(jù)段編碼鹉动,從而減少占用的硬盤大小。
比如說“10111”這個(gè)序列在圖片的二進(jìn)制數(shù)據(jù)中出現(xiàn)的概率最大宏邮,那我們可以用“01”來代替這一段數(shù)據(jù)泽示,原來5位的數(shù)據(jù),用2位就可以表示了蜜氨,這就是壓縮率60%械筛。當(dāng)然這只是打個(gè)比方,在實(shí)際操作中需要考慮“異前綴原則”等編碼的基本原則飒炎。
而如果把圖像讀取到內(nèi)存中就不一樣了埋哟,因?yàn)槲覀冃枰恳粋€(gè)像素都能在屏幕上顯示,所以會(huì)把每個(gè)像素點(diǎn)都加載至內(nèi)存中郎汪,不會(huì)對(duì)相同像素進(jìn)行壓縮或者是替換赤赊,所以你也應(yīng)該能明白前面提到的Bitmap占用內(nèi)存大小的計(jì)算公式的由來了。
說到這里煞赢,其實(shí)后兩個(gè)結(jié)論已經(jīng)解釋清楚了抛计,那么為什么“同一張圖片,放在不同目錄下照筑,會(huì)生成不同大小的Bitmap”呢爷辱?
如果你真的看懂了我之前寫的文章录豺,那么這個(gè)問題應(yīng)該不算問題朦肘。
我的測(cè)試設(shè)備為錘子T1饭弓,10801960,xxhdpi媒抠,所以說弟断,如果把這張放置在xxhdpi的話,應(yīng)該不會(huì)對(duì)圖像進(jìn)行放縮趴生,也就是原始大小阀趴,所以我們?cè)谇懊娴玫絛rawable-xxhdpi文件夾下,圖片大小為720 ?1280是完全可以理解的苍匆,就是圖片本身的大小刘急。
當(dāng)圖片放置在drawable-hdpi中時(shí),圖片大小為1440 * 2560浸踩,長(zhǎng)寬變?yōu)樵瓉淼膬杀妒逯@是因?yàn)椴煌直媛手g的倍數(shù)關(guān)系導(dǎo)致的,來一張圖
我們可以很明顯的看到xxhdpi是hdpi的2倍检碗,所以如果單獨(dú)放置在某個(gè)drawable文件夾据块,手機(jī)會(huì)自動(dòng)根據(jù)當(dāng)前的屏幕密度對(duì)圖片進(jìn)行放縮。
比如上面折剃,當(dāng)把圖片放置在xxxhdpi里面的時(shí)候另假,在xxhdpi的設(shè)備上,圖片長(zhǎng) = 720 ?(3/4) = 540怕犁,圖片寬 = 1280 ?(3/4) = 960边篮,這與上面的測(cè)試結(jié)果是完全一致的。
至于為什么在前面的測(cè)試中奏甫,drawable和drawable-mdpi是一樣的大小戈轿,是因?yàn)閐rawable-mdpi是系統(tǒng)默認(rèn)的像素密度,其他像素密度都以它為基數(shù)扶檐,當(dāng)只在drawable中存在圖片時(shí)凶杖,如果使用該圖片,那么將按照drawable-mdpi的放縮比例進(jìn)行放縮款筑。
結(jié)論
從上面的測(cè)試我們可以得出以下幾個(gè)結(jié)論:
當(dāng)圖片放置在不同drawable文件夾中智蝠,且只有這一張圖片時(shí),運(yùn)行設(shè)備會(huì)根據(jù)自身的屏幕密度奈梳,對(duì)圖片進(jìn)行放縮杈湾,放縮比例符合前面圖上的規(guī)則
圖片文件的大小與在內(nèi)存中占用的大小沒關(guān)系,內(nèi)存中實(shí)際占用大小與圖片分辨率攘须、像素顯示參數(shù)有關(guān)
所以漆撞,在一個(gè)App里面使用一套UI理論上應(yīng)該是沒有問題的,但是要注意
最好使用較高分辨率的切圖,并且放置在正確的drawable文件夾中浮驳,比如按照xxhdpi的分辨率進(jìn)行切圖悍汛,放置在drawable-xxhdpi中
對(duì)于可以使用.9格式的圖片,最好使用.9至会,減少資源大小
如果有條件离咐,最好提供多套UI切圖。如果只有一套切圖奉件,系統(tǒng)需要對(duì)圖片進(jìn)行壓縮宵蛀,會(huì)進(jìn)行大量運(yùn)算,影響設(shè)備性能县貌。同時(shí)术陶,在某些情況下,系統(tǒng)對(duì)圖片的壓縮會(huì)可能會(huì)出現(xiàn)鋸齒煤痕,造成信息的丟失
如果是多套切圖的話梧宫,最好不要直接用工具按照比例放縮,這樣小圖標(biāo)會(huì)丟失一些細(xì)節(jié)杭攻。當(dāng)然祟敛,這部分是美工來做的,可以讓她參考這篇文章利用PS CS6的新功能保持ICON細(xì)節(jié)飽滿完美
思考一下兆解,如果把一個(gè)本來應(yīng)該放在drawable-xxhdpi里面的圖片放在了drawable文件夾中會(huì)出現(xiàn)什么問題呢馆铁?
在xxhdpi設(shè)備上,圖片會(huì)被放大3倍锅睛,圖片內(nèi)存占用就會(huì)變?yōu)樵瓉淼?倍埠巨!
希望這篇文章對(duì)你有所幫助,就寫到這吧现拒,我去吃雞了辣垒!大吉大利!~