Bitmap的有關講解與優化

若蘭__明月發表於2018-01-03

Bitmap的有關講解與優化:

###1、有效處理較大的點陣圖

  • 影象有各種不同的形狀和大小,在許多情況下,他們往往比一個典型的應用程式的使用者介面UI所需要的資源更大
  • 讀取一個點陣圖的尺寸和型別:
    • 為了從多種資源來建立一個點陣圖,BitmapFactory類提供了幾個解碼的方法(decodeByteArray()),decodeFile() ,decodeResource()等等
    • 根據你的影象資料資源選擇最合適的解碼方式,這些方法檢視請求分配記憶體來構造點陣圖,因此很容易導致OOM異常,每種型別的解碼方法都有
  • 額外的特徵可以讓你通過BitMapFactory.Options方法指定解碼選項,當解碼時避免記憶體分配可以設定inJustDecodeBounds屬性為true,點陣圖物件返回null但是設定了outWidth,outHeight和outMimeType。這種技術允許你在建立點陣圖(和分配記憶體)之前去讀取影象的尺寸和型別
					BitmapFactory.Options options = new BitmapFactory.Options();
					options.inJustDecodeBounds = true;
					BitmapFactory.decodeResource(getResources(),R.id.myimage,options);
					int imageHeight = options.outHeight;
					int imageWidth = options.outWidth;
					String imageType = options.outMimeType;
複製程式碼

###2、載入一個縮小版到記憶體中:

  • 現在的圖片尺寸都是已經知道的,他們可以被用來決定是否應該載入完整的圖片到記憶體或者是否用一個縮小的版本去代替載入

  • 以下是一些值得考慮的因素: * 估計載入完整圖片所需要的記憶體 * 你承諾載入的這個圖片所需要的控制元件帶給你的程式的其他記憶體需求 * 準備載入影象的目標imageview或者UI元件尺寸 * 當前裝置的螢幕尺寸和密度

  • 例如。如果1024768畫素的影象最終被縮略的顯示在12896畫素的imageview中,就不值得載入到記憶體中告訴解碼器去重新取樣這個影象,載入一個更小的版本到記憶體中,在你的BitmapFactory.Option物件中設定inSampleSize為true

  • 例如,講一個解析度為20481536的圖片用inSampleSize值為4去編碼將產生一個大小為512384的點陣圖,載入這個倒記憶體中僅使用0.75Mb,而不是一個完整的12mb大小的圖片,(假設使用ARGB_8888點陣圖的配置)。這裡有一個方法在目標的寬度和高度的基礎上來計算一個SampleSize的值。

					/**
					 * 獲取圖片的取樣比例
					 */
					public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
					
						//獲取點陣圖的寬和高
						final int height = options.outHeight;
						final int widht = options.outWidth;
						int inSampleSize = 1;
						if (height > reqHeight || widht > reqWidth) {
								if (widht > height) {
									inSampleSize = Math.round((float) height / (float) reqHeight);
								} else {
									inSampleSize = Math.round((float) widht / (float) reqWidth);
								}
							}
							return inSampleSize;
					}
複製程式碼
  • 使用2的冪數設定inSampleSize的值可以是解碼器更快,更有效,然而,如果你想在記憶體或這個硬碟中快取一個圖片調整後的版本通常解碼到合適的影象尺寸更適合節省空間要使用這種方法。
    • 首先解碼,將inJustDecodeBounds攝者為true,將選項傳遞進去。
    • 然後在次解碼,在使用新的inSampleSize的值並將inJustDecodeBounds設定為false
					/**
					 * 圖片點陣圖重新取樣
					 *
					 * @param res
					 * @param resId
					 * @param reqWidth
					 * @param reqHeight
					 * @return
					 */
					public Bitmap decodeSampleFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
						BitmapFactory.Options options = new BitmapFactory.Options();
						options.inJustDecodeBounds = true;
						BitmapFactory.decodeResource(res, resId,options);
						options.inSampleSize = caculateInSampleSize(options, reqWidth, reqHeight);
						//再次解碼
						options.inJustDecodeBounds = false;
						return BitmapFactory.decodeResource(res, resId);
					}
複製程式碼
  • 2、快取點陣圖
    • 記憶體快取
      • 記憶體快取體用了可以快速訪問點陣圖LruCache類用於快取點陣圖的任務,最近被引用給的物件儲存在一個強引用LinkerHashMap中,以及在快取超過了其指定的大小之前釋放最近最少使用的物件的記憶體。

      • 注意:在過去,一個常用的記憶體快取實現是一個SoftReference或者WeakReference的點陣圖快取,然後現在不推薦使用,從2.3(API9)開始,垃圾回收器更加註重回收軟/弱引用,著使得使用以上的引用很大程度上無效,此外,在3.0(API11)點陣圖的備份很有可能會導致應用程式記憶體溢位和崩潰

相關文章