Android 中對(duì)于圖片的內(nèi)存優(yōu)化方法
1. 對(duì)圖片本身進(jìn)行操作
盡量不要使用 setImageBitmap、setImageResource、 BitmapFactory.decodeResource 來(lái)設(shè)置一張大圖,因?yàn)檫@些方法在完成 decode 后,最終都是通過(guò) Java 層的 createBitmap 來(lái)完成的,需要消耗更多內(nèi)存。因此,改用先通過(guò) BitmapFactory.decodeStream 方法,創(chuàng)建出一個(gè) bitmap,再將其設(shè)為 ImageView 的 source,decodeStream 最大的秘密在于其直接調(diào)用 JNI>>nativeDecodeAsset() 來(lái)完成 decode,無(wú)需再使用 Java 層的 createBitmap,從而節(jié)省了 Java 層的空間。如果在讀取時(shí)加上圖片的 Config 參數(shù),可以更有效的減少加載的內(nèi)存,從而更有效阻止拋出內(nèi)存異常。另外,decodeStream 直接拿圖片來(lái)讀取字節(jié)碼了,不會(huì)根據(jù)機(jī)器的各種分辨率來(lái)自動(dòng)適應(yīng),使用了 decodeStream 之后,需要在 hdpi 和 mdpi,ldpi 中配置相應(yīng)的圖片資源, 否則在不同分辨率機(jī)器上都是同樣大?。ㄏ袼攸c(diǎn)數(shù)量),顯示出來(lái)的大小就不對(duì)了。
InputStream is = this.getResources().openRawResource(R.drawable.pic);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 2;
Bitmap btp =BitmapFactory.decodeStream(is,null,options);
以上代碼即是讀取 drawable 下名為 pic 圖片的縮略圖,長(zhǎng)度、寬度都只有原圖片的 1/2。圖片大小減少,占用的內(nèi)存自然也變小了。這么做的弊端是圖片質(zhì)量變差,inSampleSize 的值越大,圖片的質(zhì)量就越差。由于各手機(jī)廠商縮放圖片的算法不同,在不同手機(jī)上的縮放圖片質(zhì)量可能會(huì)不同。
2. 調(diào)用圖片的 recycle() 方法
if(!bmp.isRecycle() ){
bmp.recycle() //回收?qǐng)D片所占的內(nèi)存
system.gc() //提醒系統(tǒng)及時(shí)回收
}
這種方法其實(shí)不是真正降低圖片內(nèi)存的方法。主要目的是標(biāo)記圖片對(duì)象,方便回收?qǐng)D片對(duì)象的本地?cái)?shù)據(jù)。圖片對(duì)象的本地?cái)?shù)據(jù)占用的內(nèi)存最大,而且與程序 Java 部分的內(nèi)存是分開計(jì)算的。所以經(jīng)常出現(xiàn) Java heap 足夠使用,而圖片發(fā)生 OutOfMemoryError 的情況。在圖片不使用時(shí)調(diào)用該方法,可以有效降低圖片本地?cái)?shù)據(jù)的峰值,從而減少 OutOfMemoryError 的概率。不過(guò)調(diào)用了 recycle() 的圖片對(duì)象處于“廢棄”狀態(tài),調(diào)用時(shí)會(huì)造成程序錯(cuò)誤。所以在無(wú)法保證該圖片對(duì)象絕對(duì)不會(huì)被再次調(diào)用的情況下,不建議使用該方法。特別要注意已經(jīng)用 setImageBitmap(Bitmap
img) 方法分配給控件的圖片對(duì)象,可能會(huì)被系統(tǒng)類庫(kù)調(diào)用,造成程序錯(cuò)誤。
3. 以最省內(nèi)存的方式讀取本地資源的圖片
/**
* 以最省內(nèi)存的方式讀取本地資源的圖片
*/
public static Bitmap readBitMap(Context context, int resId){
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
// 獲取資源圖片
InputStream is = context.getResources().openRawResource(resId);
return BitmapFactory.decodeStream(is,null,opt);
}
Android 中加載圖片的顏色模式有四種,分別是:ALPHA_8:每個(gè)像素占用 1byte 內(nèi)存、ARGB_4444:每個(gè)像素占用 2byte 內(nèi)存、ARGB_8888:每個(gè)像素占用 4byte 內(nèi)存、RGB_565:每個(gè)像素占用 2byte 內(nèi)存。Android默認(rèn)的顏色模式為ARGB_8888,這個(gè)顏色模式色彩最細(xì)膩,顯示質(zhì)量最高。但同樣的,占用的內(nèi)存也最大。以上代碼即是將圖片資源以 RGB_565 (或以 ARGB_4444)模式讀出。內(nèi)存減少雖然不如第一種方法明顯,但是對(duì)于大多數(shù)圖片,看不出與 ARGB_8888 模式有什么差別。不過(guò)在讀取有漸變效果的圖片時(shí),可能有顏色條出現(xiàn)。另外,會(huì)影響圖片的特效處理。
4. 使用 Matrix 對(duì)象放大的圖片如何更改顏色模式:
雖然使用 Matrix 對(duì)象放大圖片,必定會(huì)耗費(fèi)更多的內(nèi)存,但有時(shí)候也不得不這樣做。放大后的圖片使用的 ARGB_8888 顏色模式,就算原圖片是ARGB_4444 顏色模式也一樣,而且沒(méi)有辦法在放大時(shí)直接指定顏色模式??梢圆捎靡韵罗k法更改圖片顏色模式。
Matrix matrix = new Matrix();
float newWidth = 200; // 圖片放大后的寬度
float newHeight = 300; // 圖片放大后的長(zhǎng)度
matrix.postScale(newWidth / img.getWidth(), newHeight/ img.getHeight());
Bitmap img1 = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);// 得到放大圖片
img2 = img1.copy(Bitmap.Config.ARGB_4444, false); // 得到 ARGB_4444 顏色模式的圖片
img = null;
img1 = null;
這里比起本來(lái)的圖片額外生成了一個(gè)圖片對(duì)象 img1。然則體系會(huì)主動(dòng)收受接管 img1,所以實(shí)際內(nèi)存還是削減了。
歸結(jié)起來(lái)還是以縮略圖模式讀取圖片和削減圖片中每個(gè)像素占用的內(nèi)存最為有效。 這兩種辦法固然有效,然則也有各自的弊病。實(shí)際開辟中還是應(yīng)當(dāng)按照景象酌情應(yīng)用。最王道的辦法,還是避免垃圾對(duì)象的產(chǎn)生。例如在 ListView 的應(yīng)用中,復(fù)用 convertView 等。若是應(yīng)用 AsyncTask 加載圖片,要及時(shí)將引用的 ImageView 對(duì)象置為 null。因?yàn)?AsyncTask 是用線程池實(shí)現(xiàn)的,所以此中引用的對(duì)象可能會(huì)擁有很長(zhǎng)的生命周期,造成 GC 無(wú)法開釋。我還是信賴 Android 的內(nèi)存收受接管機(jī)制的,recycle 什么的固然必然程度上有效,但總感覺不合適 Java 內(nèi)存收受接管的原則。
相關(guān)文章
Android Studio快捷鍵生成TAG、Log.x日志輸出介紹
這篇文章主要介紹了Android Studio快捷鍵生成TAG、Log.x日志輸出介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04Android使用TouchDelegate增加View的觸摸范圍
這篇文章主要為大家詳細(xì)介紹了Android使用TouchDelegate增加View的觸摸范圍,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android UI控件之ListView實(shí)現(xiàn)圓角效果
這篇文章主要為大家詳細(xì)介紹了Android UI控件之ListView實(shí)現(xiàn)圓角效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Android獲取系統(tǒng)時(shí)間以及網(wǎng)絡(luò)時(shí)間
這篇文章主要為大家詳細(xì)介紹了Android獲取系統(tǒng)時(shí)間以及網(wǎng)絡(luò)時(shí)間的方法,感興趣的小伙伴們可以參考一下2016-07-07Android中自定義對(duì)話框(Dialog)的實(shí)例代碼
這篇文章介紹了Android中自定義對(duì)話框(Dialog)的實(shí)例代碼,有需要的朋友可以參考一下2013-08-08Android Service自啟動(dòng)注意事項(xiàng)分析
這篇文章主要介紹了Android Service自啟動(dòng)注意事項(xiàng),結(jié)合實(shí)例分析了Android Service自啟動(dòng)過(guò)程中屬性設(shè)置的相關(guān)技巧,需要的朋友可以參考下2016-03-03android基礎(chǔ)教程之開機(jī)啟動(dòng)示例
這篇文章主要介紹了android開機(jī)啟動(dòng)示例,開機(jī)自動(dòng)啟動(dòng)程序后開機(jī)啟動(dòng)廣播功能實(shí)現(xiàn),需要的朋友可以參考下2014-02-02Android 8.0版本更新無(wú)法自動(dòng)安裝問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了Android 8.0版本更新無(wú)法自動(dòng)安裝問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06