轉--圖片緩衝之記憶體緩衝技術LruCache,軟引用

來源:互聯網
上載者:User

標籤:

 

每當碰到一些大圖片的時候,我們如果不對圖片進行處理就會報OOM異常,
這個問題曾經讓我覺得很煩惱,後來終於得到瞭解決,
那麼現在就讓我和大家一起分享一下吧。
這篇博文要講的圖片緩衝機制,我接觸到的有兩鐘,一種是軟引用,另一種是記憶體緩衝技術。
先來看下兩者的使用方式,再來作比較。
除了載入圖片時要用到緩衝處理,還有一個比較重要的步驟要做,就是要先壓縮圖片。

1、壓縮圖片
至於要壓縮到什麼狀態就要看自己當時的處境了,壓縮圖片的時候既要達到一個小的值,又不能讓其模糊
,更不能展開圖片。
    /**
             * 載入記憶卡圖片
             */
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; // 設定了此屬性一定要記得將值設定為false
            Bitmap bitmap = null;
            bitmap = BitmapFactory.decodeFile(url, options);
            int be = (int) ((options.outHeight > options.outWidth ? options.outHeight / 150
                    : options.outWidth / 200));
            if (be <= 0) // 判斷200是否超過原始圖片高度
                be = 1; // 如果超過,則不進行縮放
            options.inSampleSize = be;
            options.inPreferredConfig = Bitmap.Config.ARGB_4444;
            options.inPurgeable = true;
            options.inInputShareable = true;
            options.inJustDecodeBounds = false;
            try {
                bitmap = BitmapFactory.decodeFile(url, options);
            } catch (OutOfMemoryError e) {
                System.gc();
                Log.e(TAG, "OutOfMemoryError");
            }

2、軟引用:
只要有足夠的記憶體,就一直保持對象,直到發現記憶體吃緊且沒有Strong Ref時才回收對象。
我們可以這樣定義:map裡面的鍵是用來放圖片地址的,既可以是網路上的圖片地址,也可以SDcard上的圖片地址,
map裡面的值裡面放的是持有軟引用的Bitmap,當然如果你要放Drawable,那也是可以的。

    private Map<String, SoftReference<Bitmap>> imageMap
                                               = new HashMap<String, SoftReference<Bitmap>>();

接下來就讓我再介紹一下如何具體載入圖片:
步驟:(1)先通過URL查看緩衝中是否有圖片,如果有,則直接去緩衝中取得。
           如果沒有,就開線程重新去網上下載。
      (2)下載完了之後,就把圖片放在緩衝裡面,方便下次可以直接從緩衝中取得。

    public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {
            SoftReference<Bitmap> reference = imageMap.get(imageUrl);
            if(reference != null) {
                if(reference.get() != null) {
                    return reference.get();
                }
            }
            final Handler handler = new Handler() {
                public void handleMessage(final android.os.Message msg) {
                    //加入到緩衝中
                    Bitmap bitmap = (Bitmap)msg.obj;
                    imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
                    if(imageCallBack != null) {
                        imageCallBack.getBitmap(bitmap);
                    }
                }
            };
            new Thread(){
                public void run() {
                    Message message = handler.obtainMessage();
                    message.obj = downloadBitmap(imageUrl);
                    handler.sendMessage(message);
                }
            }.start();
            return null ;
        }

        // 從網上下載圖片
        private Bitmap downloadBitmap (String imageUrl) {
            Bitmap bitmap = null;
            try {
                bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
                return bitmap ;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public interface ImageCallBack{
            void getBitmap(Bitmap bitmap);
        }



3、記憶體緩衝技術
另外一種圖片緩衝的方式就是記憶體緩衝技術。在Android中,有一個叫做LruCache類專門用來做圖片緩衝處理的。
它有一個特點,當緩衝的圖片達到了預先設定的值的時候,那麼近期使用次數最少的圖片就會被回收掉。
步驟:(1)要先設定緩衝圖片的記憶體大小,我這裡設定為手機記憶體的1/8,
           手機記憶體的擷取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
      (2)LruCache裡面的索引值對分別是URL和對應的圖片
      (3)重寫了一個叫做sizeOf的方法,返回的是圖片數量。

    private LruCache<String, Bitmap> mMemoryCache;
    private LruCacheUtils() {
            if (mMemoryCache == null)
                mMemoryCache = new LruCache<String, Bitmap>(
                        MAXMEMONRY / 8) {
                    @Override
                    protected int sizeOf(String key, Bitmap bitmap) {
                        // 重寫此方法來衡量每張圖片的大小,預設返回圖片數量。

     return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
                    }

                    @Override
                    protected void entryRemoved(boolean evicted, String key,
                            Bitmap oldValue, Bitmap newValue) {
                        Log.v("tag", "hard cache is full , push to soft cache");
                      
                    }
                };
        }
     (4)下面的方法分別是清空緩衝、添加圖片到緩衝、從緩衝中取得圖片、從緩衝中移除。
          移除和清除緩衝是必須要做的事,因為圖片緩衝處理不當就會報記憶體溢出,所以一定要引起注意。

    public void clearCache() {
            if (mMemoryCache != null) {
                if (mMemoryCache.size() > 0) {
                    Log.d("CacheUtils",
                            "mMemoryCache.size() " + mMemoryCache.size());
                    mMemoryCache.evictAll();
                    Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());
                }
                mMemoryCache = null;
            }
        }

        public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
            if (mMemoryCache.get(key) == null) {
                if (key != null && bitmap != null)
                    mMemoryCache.put(key, bitmap);
            } else
                Log.w(TAG, "the res is aready exits");
        }

        public synchronized Bitmap getBitmapFromMemCache(String key) {
            Bitmap bm = mMemoryCache.get(key);
            if (key != null) {
                return bm;
            }
            return null;
        }

        /**
         * 移除緩衝
         *
         * @param key
         */
        public synchronized void removeImageCache(String key) {
            if (key != null) {
                if (mMemoryCache != null) {
                    Bitmap bm = mMemoryCache.remove(key);
                    if (bm != null)
                        bm.recycle();
                }
            }
        }

4、兩者的比較
說到這裡,我覺得有必要來進行一下比較了。
網上有很多人使用軟引用載入圖片的多 ,但是現在已經不再推薦使用這種方式了,
(1)因為從 Android 2.3 (API Level 9)開始,記憶體回收行程會更傾向於回收持有軟引用或弱引用的對象,
     這讓軟引用和弱引用變得不再可靠。
(2)另外,Android 3.0 (API Level 11)中,圖片的資料會儲存在本地的記憶體當中,
     因而無法用一種可預見的方式將其釋放,這就有潛在的風險造成應用程式的記憶體溢出並崩潰,
所以我這裡用得是LruCache來緩衝圖片,當儲存Image的大小大於LruCache設定的值,系統自動釋放記憶體,
這個類是3.1版本中提供的,如果你是在更早的Android版本中開發,則需要匯入android-support-v4的jar包。

後記:我一直有強調一件事件,就是人應該要不停地進步,沒有人生來就會編碼,
更沒有人一開始就能找到很好的解決方案,我介紹了這兩種用法,

 

轉--圖片緩衝之記憶體緩衝技術LruCache,軟引用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.