釋放雙眼,帶上耳機,聽聽看~!
本篇文章介紹了android記憶體優化之圖檔優化,下面小編給大家介紹詳細的解決步驟
對圖檔本身進行操作。盡量不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設定一張大圖,因為這些方法在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體。是以,改用先通過BitmapFactory.decodeStream方法,建立出一個bitmap,再将其設為ImageView的source,decodeStream最大的秘密在于其直接調用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,進而節省了java層的空間。如果在讀取時加上圖檔的Config參數,可以更有效的減少加載的記憶體,進而更有效阻止抛出記憶體異常。另外,decodeStream直接拿圖檔來讀取位元組碼了,不會根據機器的各種分辨率來自動适應,使用了decodeStream之後,需要在hdpi和mdpi,ldpi中配置相應的圖檔資源,否則在不同分辨率機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。
InputStreamis=this.getResources().openRawResource(R.drawable.pic1);
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=false;
options.inSampleSize=10;//width,hight設為原來的十分一
Bitmapbtp=BitmapFactory.decodeStream(is,null,options);
if(!bmp.isRecycle()){
bmp.recycle()//回收圖檔所占的記憶體
system.gc()//提醒系統及時回收
}
publicstaticBitmapreadBitMap(Contextcontext,intresId){
BitmapFactory.Optionsopt=newBitmapFactory.Options();
opt.inPreferredConfig=Bitmap.Config.RGB_565;
opt.inPurgeable=true;
opt.inInputShareable=true;
//擷取資源圖檔
InputStreamis=context.getResources().openRawResource(resId);
returnBitmapFactory.decodeStream(is,null,opt);
}
option中的值指的是,圖檔進行縮放的比例,SDK中建議其值是2的指數值,值越大會導緻圖檔不清晰。長度、寬度都隻有原圖檔的1/2。圖檔大小減少,占用的記憶體自然也變小了。這麼做的弊端是圖檔品質變差,inSampleSize的值越大,圖檔的品質就越差。由于各手機廠商縮放圖檔的算法不同,在不同手機上的縮放圖檔品質可能會不同。筆者就遭遇過moto手機上圖檔縮放後品質可以接受,三星手機上同樣的縮放比例,品質卻差很多的情況。
Android中有四種,分别是:
ALPHA_8:每個像素占用1byte記憶體
ARGB_4444:每個像素占用2byte記憶體
ARGB_8888:每個像素占用4byte記憶體
RGB_565:每個像素占用2byte記憶體
Android預設的顔色模式為ARGB_8888,這個顔色模式色彩最細膩,顯示品質最高。但同樣的,占用的記憶體也最大。
以上代碼即是将1.png以ARGB_4444模式讀出。記憶體減少雖然不如第一種方法明顯,但是對于大多數圖檔,看不出與ARGB_8888模式有什麼差别。不過在讀取有漸變效果的圖檔時,可能有顔色條出現。另外,會影響圖檔的特效處理。
優化Dalvik虛拟機的堆記憶體配置設定。對于Android平台來說,其托管層使用的DalvikJavaVM從目前的表現來看還有很多地方可以優化處理,比如我們在開發一些大型遊戲或耗資源的應用中可能考慮手動幹涉GC處理,使用dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強程式堆記憶體的處理效率。使用方法:
privatefinalstaticfloatTARGET_HEAP_UTILIZATION=0.75f;
VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
即可。
還有就是可以定義堆記憶體的大小。
privatefinalstaticintCWJ_HEAP_SIZE=6*1024*1024;VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);//設定最小heap記憶體為6MB大小
調用圖檔的recycle()方法:
這個其實不是真正降低圖檔記憶體的方法。主要目的是标記圖檔對象,友善回收圖檔對象的本地資料。圖檔對象的本地資料占用的記憶體最大,而且與程式Java部分的記憶體是分開計算的。是以經常出現Javaheap足夠使用,而圖檔發生OutOfMemoryError的情況。在圖檔不使用時調用該方法,可以有效降低圖檔本地資料的峰值,進而減少OutOfMemoryError的機率。不過調用了recycle()的圖檔對象處于“廢棄”狀态,調用時會造成程式錯誤。是以在無法保證該圖檔對象絕對不會被再次調用的情況下,不建議使用該方法。特别要注意已經用setImageBitmap(Bitmapimg)方法配置設定給控件的圖檔對象,可能會被系統類庫調用,造成程式錯誤。
使用Matrix對象放大的圖檔如何更改顔色模式:
雖然使用Matrix對象放大圖檔,必定會耗費更多的記憶體,但有時候也不得不這樣做。放大後的圖檔使用的ARGB_8888顔色模式,就算原圖檔是ARGB_4444顔色模式也一樣,而且沒有辦法在放大時直接指定顔色模式。可以采用以下辦法更改圖檔顔色模式。
代碼如下
Matrixmatrix=newMatrix();
floatnewWidth=200;//圖檔放大後的寬度
floatnewHeight=300;//圖檔放大後的長度
matrix.postScale(newWidth/img.getWidth(),newHeight/img.getHeight());
Bitmapimg1=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;
這裡比起原來的圖檔額外生成了一個圖檔對象img1。但是系統會自動回收img1,是以實際記憶體還是減少了。