Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 分享一個輕量級圖片加載類 ImageLoader

分享一個輕量級圖片加載類 ImageLoader

編輯:關於Android編程

ImageLoader 這類的 圖片加載網絡上一大推,像比較出名的有nostra13 的-Image-Loader圖片加載,xUtil的圖片加載,還有 Facebook 的 Fresco 。很多,但本著求學的態度,最近在做項目時有圖片加載這個需求就自己寫了個輕量級的 (本地)圖片緩存加載 功能,分享給各位。

裡面涉及了 LruCache ,ExecutorService,處理大圖的 BitmapFactory 原理,view.setTag() .

好了,不多說,先一步一步來:
首先看一下我封裝的類怎麼使用:

    // 本地照片絕對路徑
    String imageUrl = (String) t;
    // 得到 ImageView 
    ImageView grid_item = holder.getView(R.id.grid_item);
    // 設置 tag ,標記用的,反正圖片顯示錯位
    grid_item.setTag(imageUrl);
    
     /**
     * 顯示 圖片
     * 
     * @param context
     *      : 上下文
     * @param imageView
     *      : ImageView 控件
     * @param sourcePath
     *      : 圖片 地址
     * @param r_Id
     *      : 默認 圖片 id ,R.drowable.id;
     * @param callback
     *      :圖片顯示 回調
     */
 
    new ImageLoader().displayBmp(mContext,grid_item, imageUrl, R.drawable.img_bg,this);
 

是不是很簡單。

接下來具體分析 ImageLoader 這個類:

都知道手機的內存有限,不可能將所有的圖片都加進內存,所以android 提供了一個 LruCache 方法,用到的 算法 是 :近期最少使用算法 ,及在圖片不斷的加進緩存,最少使用的圖片也在不斷的移除緩存 ,從而避免的內存不夠的問題。

LruCache 的初始化代碼如下:

  public ImageLoader() {

    // 取應用內存的 8/1 作為 圖片緩存用
    int cacheSize = maxMemory / 8;
    // 得到 LruCache
    mLruCache = new LruCache<String, Bitmap>(cacheSize) {
      @Override
      protected int sizeOf(String key, Bitmap bitmap) {
        return bitmap.getByteCount();
      }
    };

  }

  /**
   * 將圖片存儲到LruCache
   */
  public void putBitmapToLruCache(String key, Bitmap bitmap) {
    if (getBitmapFromLruCache(key) == null && mLruCache != null) {
      mLruCache.put(key, bitmap);
    }
  }
  /**
   * 從LruCache緩存獲取圖片
   */
  public Bitmap getBitmapFromLruCache(String key) {
    return mLruCache.get(key);
  }

LruCache 就像 HashMap 一樣 利用put 和 get 得到緩存的東西。

接著看 圖片的 具體加載,先把代碼貼出來:

  /**
   * 顯示 圖片
   * 
   * @param context
   *      : 上下文
   * @param imageView
   *      : ImageView 控件
   * @param sourcePath
   *      : 圖片 地址
   * @param r_Id
   *      : 默認 圖片 id ,R.drowable.id;
   * @param callback
   *      :圖片顯示 回調
   */
  public void displayBmp(final Context context, final ImageView imageView, final String sourcePath, final int r_Id,
      final ImageCallback callback) {

    final String path;

    if (!TextUtils.isEmpty(sourcePath)) {
      path = sourcePath;

    } else {
      return;
    }
    // 先 試著 從 緩存 得到 圖片 , path 作為 圖片的 key
    Bitmap bmp = mLruCache.get(path);

    if (bmp != null) {
      if (callback != null) {
        // 回調 圖片 顯示
        callback.imageLoad(imageView, bmp, sourcePath);
      }
      // imageView.setImageBitmap(bmp);
      return;
    }
    // 如果 bmp == null ,給 imageView 顯示默認圖片
    imageView.setImageResource(r_Id);
    // 啟動 線程池
    threadPoolUtils.getExecutorService().execute(new Runnable() {
      Bitmap bitmap = null;

      @Override
      public void run() {
        // TODO Auto-generated method stub

        try {
          // 加載 圖片 地址 對應 的 縮略圖
          bitmap = revitionImageSize(imageView, sourcePath);
        } catch (Exception e) {

        }
        if (bitmap == null) {
          try {
            // 如果 縮略圖 沒加載成功 顯示 默認 設置的圖片
            bitmap = BitmapFactory.decodeResource(context.getResources(), r_Id);
          } catch (Exception e) {
          }
        }
        if (path != null && bitmap != null) {
          // 將 縮略圖 放進 緩存 , path 作為 key
          putBitmapToLruCache(path, bitmap);
        }

        if (callback != null) {
          handler.post(new Runnable() {
            @Override
            public void run() {
              // 回調 圖片 顯示
              callback.imageLoad(imageView, bitmap, sourcePath);

            }
          });
        }

      }
    });

  }

代碼不是狠多,主要就是 先從緩存加載圖片,當加載圖片為空時,再從手機的圖片地址加載圖片

bitmap = revitionImageSize(imageView, sourcePath);

加載緩存圖片就不多說了,看的也明白, mLruCache.get(key);就這麼簡單

具體分析 revitionImageSize() 這個方法吧:

  public Bitmap revitionImageSize(ImageView imageView, String path) throws IOException {

    // 得到 布局 ImageView 的 寬高
    int img_width = imageView.getWidth();
    int img_height = imageView.getHeight();
 
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(path)));
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeStream(in, null, options);
    in.close();

    int height = options.outHeight;
    int width = options.outWidth;

    Bitmap bitmap = null;
 
    int inSampleSize = 1;

    // 計算出實際寬高和目標寬高的比率
    final int heightRatio = Math.round((float) height / (float) img_height);
    final int widthRatio = Math.round((float) width / (float) img_width);
    // 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高
    // 一定都會大於等於目標的寬和高。
    inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    // 調用上面定義的方法計算inSampleSize值
    options.inSampleSize = inSampleSize;

    options.inJustDecodeBounds = false;
    in = new BufferedInputStream(new FileInputStream(new File(path)));
    bitmap = BitmapFactory.decodeStream(in, null, options);

    in.close();
    return bitmap;
  }

代碼我也寫了注釋了 ,一般在加載圖片時都有對圖片一定的壓縮處理避免OOM,所以上面的處理方法也是挺常見的,對要顯示 圖片 根據 imageview 控件大小進行一定的壓縮。

如果對 圖片壓縮處理不是很理解的朋友這麼我簡單解釋一下:

首先加載完圖片:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(path)));

然後:

options.inJustDecodeBounds = true;

再接著:

int height = options.outHeight;
int width = options.outWidth;

這時候注意 程序並沒有把圖片真正的加載進來,options.inJustDecodeBounds = true;

這句在起作用,但圖片的寬和高 的信息我們卻得到了,就可以處理壓縮圖片了!

壓縮完圖片再:

options.inJustDecodeBounds = false;

重新得到壓縮後的圖片:

bitmap = BitmapFactory.decodeStream(in, null, options);

解釋完畢。

仔細看代碼的同學會發現 displayBmp() 方法裡面有個 回調參數:

回調接口如下:

  /**
   * 顯示圖片回調
   * 
   * @author Administrator
   *
   */
  public interface ImageCallback {
    public void imageLoad(ImageView imageView, Bitmap bitmap, Object... params);
  }

具體實現是在顯示圖片的地方回調的:

   /**
   * 圖片 緩存回調
   */
  @Override
  public void imageLoad(ImageView imageView, Bitmap bitmap, Object... params) {
    if (imageView != null && bitmap != null) {
      String url = (String) params[0];

      // 判斷 這裡的 url 是否 對應 imageView.getTag()
      // 如果 將這句 判斷 去掉 那麼 就會出現 經常出現的 圖片 顯示 錯位 問題 !!!!
      if (url != null && url.equals((String) imageView.getTag())) {

        ((ImageView) imageView).setImageBitmap(bitmap);
      }
    }
  }

代碼注釋的地方也寫了,不太理解的同學可以私信交流,另外附上我 github github連接上的源碼,可以下載下了運行方便好理解:

為了你方便使用,在你的項目中添加如下依賴即可:

dependencies {
      compile 'com.zts:imageloader:1.1.1'

  }

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved