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); } }