Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 詳解Android 圖片的三級緩存及圖片壓縮

詳解Android 圖片的三級緩存及圖片壓縮

編輯:關於Android編程

為什麼需要圖片緩存

Android默認給每個應用只分配16M的內存,所以如果加載過多的圖片,為了防止內存溢出,應該將圖片緩存起來。圖片的三級緩存分別是:

  • 內存緩存
  • 本地緩存
  • 網絡緩存

其中,內存緩存應優先加載,它速度最快;本地緩存次優先加載,它速度也快;網絡緩存不應該優先加載,它走網絡,速度慢且耗流量。

三級緩存的具體實現

網絡緩存

  • 根據圖片的url去加載圖片
  • 在本地和內存中緩存

  

 public class NetCacheUtils {

    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public NetCacheUtils(LocalCacheUtils localCacheUtils,
        MemoryCacheUtils memoryCacheUtils) {
      mLocalCacheUtils = localCacheUtils;
      mMemoryCacheUtils = memoryCacheUtils;
    }

    /**
     * 從網絡下載圖片
     * 
     * @param ivPic
     * @param url
     */
    public void getBitmapFromNet(ImageView ivPic, String url) {
      new BitmapTask().execute(ivPic, url);// 啟動AsyncTask,
                          // 參數會在doInbackground中獲取
    }

    /**
     * Handler和線程池的封裝
     * 
     * 第一個泛型: 參數類型 第二個泛型: 更新進度的泛型, 第三個泛型是onPostExecute的返回結果
     * 
     * 
     */
    class BitmapTask extends AsyncTask<Object, Void, Bitmap> {

      private ImageView ivPic;
      private String url;

      /**
       * 後台耗時方法在此執行, 子線程
       */
      @Override
      protected Bitmap doInBackground(Object... params) {
        ivPic = (ImageView) params[0];
        url = (String) params[1];

        ivPic.setTag(url);// 將url和imageview綁定

        return downloadBitmap(url);
      }

      /**
       * 更新進度, 主線程
       */
      @Override
      protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
      }

      /**
       * 耗時方法結束後,執行該方法, 主線程
       */
      @Override
      protected void onPostExecute(Bitmap result) {
        if (result != null) {
          String bindUrl = (String) ivPic.getTag();

          if (url.equals(bindUrl)) {// 確保圖片設定給了正確的imageview
            ivPic.setImageBitmap(result);
            mLocalCacheUtils.setBitmapToLocal(url, result);// 將圖片保存在本地
            mMemoryCacheUtils.setBitmapToMemory(url, result);// 將圖片保存在內存
            System.out.println("從網絡緩存讀取圖片啦...");
          }
        }
      }
    }

    /**
     * 下載圖片
     * 
     * @param url
     * @return
     */
    private Bitmap downloadBitmap(String url) {

      HttpURLConnection conn = null;
      try {
        conn = (HttpURLConnection) new URL(url).openConnection();

        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);
        conn.setRequestMethod("GET");
        conn.connect();

        int responseCode = conn.getResponseCode();
        if (responseCode == 200) {
          InputStream inputStream = conn.getInputStream();

          //圖片壓縮處理
          BitmapFactory.Options option = new BitmapFactory.Options();
          option.inSampleSize = 2;//寬高都壓縮為原來的二分之一, 此參數需要根據圖片要展示的大小來確定
          option.inPreferredConfig = Bitmap.Config.RGB_565;//設置圖片格式

          Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
          return bitmap;
        }

      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        conn.disconnect();
      }

      return null;
    }
  }

本地緩存

兩個方法:設置本地緩存,獲取本地緩存

  public class LocalCacheUtils {

    public static final String CACHE_PATH = Environment
        .getExternalStorageDirectory().getAbsolutePath() + "/local_cache";

    /**
     * 從本地sdcard讀圖片
     */
    public Bitmap getBitmapFromLocal(String url) {
      try {
        String fileName = MD5Encoder.encode(url);
        File file = new File(CACHE_PATH, fileName);

        if (file.exists()) {
          Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
              file));
          return bitmap;
        }

      } catch (Exception e) {
        e.printStackTrace();
      }

      return null;
    }

    /**
     * 向sdcard寫圖片
     * 
     * @param url
     * @param bitmap
     */
    public void setBitmapToLocal(String url, Bitmap bitmap) {
      try {
        String fileName = MD5Encoder.encode(url);

        File file = new File(CACHE_PATH, fileName);

        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {// 如果文件夾不存在, 創建文件夾
          parentFile.mkdirs();
        }

        // 將圖片保存在本地
        bitmap.compress(CompressFormat.JPEG, 100,
            new FileOutputStream(file));
      } catch (Exception e) {
        e.printStackTrace();
      }

    }
  }

內存緩存

兩個方法:設置內存緩存,獲取內存緩存

問題:

如果使用HashMap存儲圖片時,當圖片越來越多時,會導致內存溢出,因為它是強引用,java的垃圾回收器不會回收。

如若改成軟引用SoftReference(內存不夠時,垃圾回收器會考慮回收),仍有一個問題:在android2.3+, 系統會優先將SoftReference的對象提前回收掉, 即使內存夠用。

解決辦法:可以用LruCache來解決上述內存不回收或提前回收的問題。least recentlly use 最少最近使用算法 它會將內存控制在一定的大小內, 超出最大值時會自動回收, 這個最大值開發者自己定
 

    public class MemoryCacheUtils {

      // private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new
      // HashMap<String, SoftReference<Bitmap>>();
      private LruCache<String, Bitmap> mMemoryCache;

      public MemoryCacheUtils() {
        long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模擬器默認是16M
        mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
          @Override
          protected int sizeOf(String key, Bitmap value) {
            int byteCount = value.getRowBytes() * value.getHeight();// 獲取圖片占用內存大小
            return byteCount;
          }
        };
      }

      /**
       * 從內存讀
       * 
       * @param url
       */
      public Bitmap getBitmapFromMemory(String url) {
        // SoftReference<Bitmap> softReference = mMemoryCache.get(url);
        // if (softReference != null) {
        // Bitmap bitmap = softReference.get();
        // return bitmap;
        // }
        return mMemoryCache.get(url);
      }

      /**
       * 寫內存
       * 
       * @param url
       * @param bitmap
       */
      public void setBitmapToMemory(String url, Bitmap bitmap) {
        // SoftReference<Bitmap> softReference = new
        // SoftReference<Bitmap>(bitmap);
        // mMemoryCache.put(url, softReference);
        mMemoryCache.put(url, bitmap);
      }
    }

圖片壓縮

  //圖片壓縮處理(在從網絡獲取圖片的時候就進行壓縮)
  BitmapFactory.Options option = new BitmapFactory.Options();
  option.inSampleSize = 2;//寬高都壓縮為原來的二分之一, 此參數需要根據圖片要展示的大小來確定
  option.inPreferredConfig = Bitmap.Config.RGB_565;//設置圖片格式
  Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

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