Android中Bitmap記憶體溢出(OOM)的解決方案

來源:互聯網
上載者:User

做公司的android應用,功能很簡單,ViewFlipper中用GestureDetector實現滑動切換圖片。重寫onFling() 方法,判斷手指滑動方向,將Bitmap載入到一個imageView中,在調用viewFlipper的addView()方法,再將imageView載入到viewFlipper中。  最不好解決的就是Bitmap的Out
of Memory問題,載入很多圖之後會報記憶體溢出的錯誤。 關於這個問題的,網上搜了很多解決方案,沒有很好的解決方案,恰巧碰到群裡也有人遇到過這種問題,現將我找到的解決方案總結如下,後面我會給出自己的解決方案。

1. 設定BitmapFactory的options 代碼如下:

BitmapFactory.Options options = new BitmapFactory.Options();options.inSampleSize = 3;Bitmap bitmap = BitmapFactory.decodeStream(is, null, ops);

設定的inSampleSize就是將圖片的長寬壓縮,設定為3意味著,產生的圖片長寬各為原長度的1/3。 這個方法只是對效能的一種最佳化,並沒有從根本上解決記憶體的問題,當載入的Bitmap過多時,依然會有記憶體溢出的問題。 2.
使用SoftReference實現圖片的緩衝
 代碼不貼了,這裡有詳細的實現方式,以及關於軟引用的介紹: http://www.cnblogs.com/dwinter/archive/2012/01/30/2331556.html 實現的原理就是建立一個softreference用來存放圖片和索引,因為softreference容易被GC回收,從而釋放佔用的記憶體。 但是親自實現下來並沒有很好的解決OOM的問題。個人謹慎猜測是因為viewFlipper佔用著包含Bitmap的imageView,所以引用一直存在,GC並不會自動回收。 3.
調用Bitmap的recycle( )方法回收Bitmap
 判斷圖片id號為current-2和current+2的Bitmap的isRecycled( ),如果沒有被回收的話,調用recycle( )強制回收。 其實這個方法效果很好,只是當想但會瀏覽圖片時會出現“試圖載入已經被回收的Bitmap“的錯誤。 我自認為程式寫的沒什麼問題(估計還是有問題),最後就放棄了這個方法。 4.
建立LruCache使圖片的載入更有效率
 這個方法在Google的官方文檔上是有的,連結如下: http://developer.android.com/training/displaying-bitmaps/index.html 實現的原理就是建立一個LruCache,這樣可以對圖片有效率的顯示和利用。 第二種方法提到過softReference,這個文章中是不推薦這樣做的,具體原因可以詳細的閱讀以下。 LruCache是在API
Level 11中加入的,那Android 2.2 神馬的怎麼辦?沒關係,手動寫一個LruCache,或者找一個。我貼一個出來吧。

/** * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.guju.service;import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.Map;/*** * An LRU cache which stores recently inserted entries and all entries ever * inserted which still has a strong reference elsewhere. */public class LruCache<K, V> {    private final HashMap<K, V> mLruMap;    private final HashMap<K, Entry<K, V>> mWeakMap =            new HashMap<K, Entry<K, V>>();    private ReferenceQueue<V> mQueue = new ReferenceQueue<V>();    @SuppressWarnings("serial")    public LruCache(final int capacity) {        mLruMap = new LinkedHashMap<K, V>(16, 0.75f, true) {            @Override            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {                return size() > capacity;            }        };    }    private static class Entry<K, V> extends WeakReference<V> {        K mKey;        public Entry(K key, V value, ReferenceQueue<V> queue) {            super(value, queue);            mKey = key;        }    }    @SuppressWarnings("unchecked")    private void cleanUpWeakMap() {        Entry<K, V> entry = (Entry<K, V>) mQueue.poll();        while (entry != null) {            mWeakMap.remove(entry.mKey);            entry = (Entry<K, V>) mQueue.poll();        }    }    public synchronized V put(K key, V value) {        cleanUpWeakMap();        mLruMap.put(key, value);        Entry<K, V> entry = mWeakMap.put(                key, new Entry<K, V>(key, value, mQueue));        return entry == null ? null : entry.get();    }    public synchronized V get(K key) {        cleanUpWeakMap();        V value = mLruMap.get(key);        if (value != null) return value;        Entry<K, V> entry = mWeakMap.get(key);        return entry == null ? null : entry.get();    }    public synchronized void clear() {        mLruMap.clear();        mWeakMap.clear();        mQueue = new ReferenceQueue<V>();    }}

可以直接拿來用哦親~不過記得留著人家的著作權聲明,這是最起碼的。 其實我試過以上所有的方法,問題還沒解決——即使是在建立一個LruCache之後。 在stackoverflow上提過問題之後,有個人的回答是要調用removeView(
) 釋放Bitmap。 恍然大悟啊!好了,問題解決了。

imageView.setImageBitmap(bitmap);imageView.setScaleType(ImageView.ScaleType.CENTER);viewFlipper.removeAllViews();viewFlipper.addView(imageView);

每次addView之前,remove掉之前的view就可以了。 當然,設定BitmapFactory的options以及建立LruCache也是很必須的,能夠更好的提供圖片瀏覽的體驗。 不過產生一個新問題就是添加Animation的問題,如果直接調用removeView的話,那個view的動畫效果就不容易設定。   希望對用到的人有些協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.