Android緩存的引用

package com.example.imagescan;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;

/**
 * 本地圖片加載器,採用的是異步解析本地圖片,單例模式利用getInstance()獲取NativeImageLoader實例
 * 調用loadNativeImage()方法加載本地圖片,此類可做爲一個加載本地圖片的工具類
 * 
 * @blog http://blog.csdn.net/xiaanming
 * 
 * @author xiaanming
 *
 */
public class NativeImageLoader {
	private LruCache<String, Bitmap> mMemoryCache;
	private static NativeImageLoader mInstance = new NativeImageLoader();
	private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);
	
	
	
	private NativeImageLoader(){
		//獲取應用程序的最大內存
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

		//用最大內存的1/4來存儲圖片
		final int cacheSize = maxMemory / 4;
		mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
			
			//獲取每張圖片的大小
			@Override
			protected int sizeOf(String key, Bitmap bitmap) {
				return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
			}
		};
	}
	
	/**
	 * 經過此方法來獲取NativeImageLoader的實例
	 * @return
	 */
	public static NativeImageLoader getInstance(){
		return mInstance;
	}
	
	
	/**
	 * 加載本地圖片,對圖片不進行裁剪
	 * @param path
	 * @param mCallBack
	 * @return
	 */
	public Bitmap loadNativeImage(final String path, final NativeImageCallBack mCallBack){
		return this.loadNativeImage(path, null, mCallBack);
	}
	
	/**
	 * 此方法來加載本地圖片,這裏的mPoint是用來封裝ImageView的寬和高,咱們會根據ImageView控件的大小來裁剪Bitmap
	 * 若是你不想裁剪圖片,調用loadNativeImage(final String path, final NativeImageCallBack mCallBack)來加載
	 * @param path
	 * @param mPoint
	 * @param mCallBack
	 * @return
	 */
	public Bitmap loadNativeImage(final String path, final Point mPoint, final NativeImageCallBack mCallBack){
		//先獲取內存中的Bitmap
		Bitmap bitmap = getBitmapFromMemCache(path);
		
		final Handler mHander = new Handler(){

			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				mCallBack.onImageLoader((Bitmap)msg.obj, path);
			}
			
		};
		
		//若該Bitmap不在內存緩存中,則啓用線程去加載本地的圖片,並將Bitmap加入到mMemoryCache中
		if(bitmap == null){
			mImageThreadPool.execute(new Runnable() {
				
				@Override
				public void run() {
					//先獲取圖片的縮略圖
					Bitmap mBitmap = decodeThumbBitmapForFile(path, mPoint == null ? 0: mPoint.x, mPoint == null ? 0: mPoint.y);
					Message msg = mHander.obtainMessage();
					msg.obj = mBitmap;
					mHander.sendMessage(msg);
					
					//將圖片加入到內存緩存
					addBitmapToMemoryCache(path, mBitmap);
				}
			});
		}
		return bitmap;
		
	}

	
	
	/**
	 * 往內存緩存中添加Bitmap
	 * 
	 * @param key
	 * @param bitmap
	 */
	private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
		if (getBitmapFromMemCache(key) == null && bitmap != null) {
			mMemoryCache.put(key, bitmap);
		}
	}

	/**
	 * 根據key來獲取內存中的圖片
	 * @param key
	 * @return
	 */
	private Bitmap getBitmapFromMemCache(String key) {
		return mMemoryCache.get(key);
	}
	
	
	/**
	 * 根據View(主要是ImageView)的寬和高來獲取圖片的縮略圖
	 * @param path
	 * @param viewWidth
	 * @param viewHeight
	 * @return
	 */
	private Bitmap decodeThumbBitmapForFile(String path, int viewWidth, int viewHeight){
		BitmapFactory.Options options = new BitmapFactory.Options();
		//設置爲true,表示解析Bitmap對象,該對象不佔內存
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);
		//設置縮放比例
		options.inSampleSize = computeScale(options, viewWidth, viewHeight);
		
		//設置爲false,解析Bitmap對象加入到內存中
		options.inJustDecodeBounds = false;
		
		return BitmapFactory.decodeFile(path, options);
	}
	
	
	/**
	 * 根據View(主要是ImageView)的寬和高來計算Bitmap縮放比例。默認不縮放
	 * @param options
	 * @param width
	 * @param height
	 */
	private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight){
		int inSampleSize = 1;
		if(viewWidth == 0 || viewWidth == 0){
			return inSampleSize;
		}
		int bitmapWidth = options.outWidth;
		int bitmapHeight = options.outHeight;
		
		//假如Bitmap的寬度或高度大於咱們設定圖片的View的寬高,則計算縮放比例
		if(bitmapWidth > viewWidth || bitmapHeight > viewWidth){
			int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);
			int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);
			
			//爲了保證圖片不縮放變形,咱們取寬高比例最小的那個
			inSampleSize = widthScale < heightScale ? widthScale : heightScale;
		}
		return inSampleSize;
	}
	
	
	/**
	 * 加載本地圖片的回調接口
	 * 
	 * @author xiaanming
	 *
	 */
	public interface NativeImageCallBack{
		/**
		 * 當子線程加載完了本地的圖片,將Bitmap和圖片路徑回調在此方法中
		 * @param bitmap
		 * @param path
		 */
		public void onImageLoader(Bitmap bitmap, String path);
	}
}
相關文章
相關標籤/搜索