做公司的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的動畫效果就不容易設定。 希望對用到的人有些協助。