我使用下面的LRU类来管理位图,使用我正在创建的这两个类并删除位图以将它们放在viewpager视图上。相同的代码正在4.2版本以下,但当我在4.2或更高版本上加载我的应用程序时,我切换页面时堆大小不断增加。问题是我能够在4.2或更高版本中回收位图,而不是堆大小正在增加。他们是否有任何其他方式在4.2或更高版本中释放堆大小。请帮我解决这个问题
public class LruMemoryCache extends LruSoftCache<String, Bitmap> {
private String TAG = "LruMemoryCache";
public LruMemoryCache(int size) {
super(size);
}
@Override
protected Bitmap create(Context con, String key) {
// Log.d(TAG,"######----create bitmap-----############"+size());
try {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
return BitmapFactory.decodeFile(key, options);
// return BitmapFactory.decodeFile(key);
} catch (OutOfMemoryError e) {
Log.d(TAG, "######---- bitmap Handled-----############");
Utility.freeMemory();
}
return null;
// return
// ShrinkBitmap(key,ViewMagazineActivity.Width,ViewMagazineActivity.Height);
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,
Bitmap newValue) {
if (!evicted) {
if (oldValue != null) {
Log.v(TAG, "============----IMage is recycled-----==========="
+ key);
oldValue.recycle();
oldValue = null;
}
Utility.freeMemory();
}
}
@TargetApi(12)
protected int sizeOf(String key, Bitmap value) {
if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) {
Log.e(TAG, "Memory occupy by bitmap-------" + value.getByteCount()
/ 131072);
return value.getByteCount();
} else {
Log.e(TAG, "Memory occupy by bitmap-------"
+ (value.getRowBytes() * value.getHeight()) / 131072);
return (value.getRowBytes() * value.getHeight());
}
}
}
public class LruSoftCache<K, V> {
private static final String LOG_TAG = LruSoftCache.class.getSimpleName();
private final LinkedHashMap<K, SoftReference<V>> map;
/** Size of this cache in units. Not necessarily the number of elements. */
private int size;
private int maxSize;
private int putCount;
private int createCount;
private int evictionCount;
private int hitCount;
private int missCount;
/**
* @param maxSize
* for caches that do not override {@link #sizeOf}, this is the
* maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this
* cache.
*/
public LruSoftCache(int maxSize) {
Log.v("LruSoftCache", "Constructor called");
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, SoftReference<V>>(0, 0.75f, true);
}
/**
* Returns the value for {@code key} if it exists in the cache or can be
* created by {@code #create}. If a value was returned, it is moved to the
* head of the queue. This returns null if a value is not cached and cannot
* be created.
*/
public final V get(Context context, K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
Log.v("LruSoftCache", "-----GET Method is called" + key);
SoftReference<V> mapValue;
V mapReferent = null;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
mapReferent = mapValue.get();
}
if (mapReferent != null) {
hitCount++;
return mapReferent;
}
if (mapValue != null) {
size -= safeSizeOf(key, null);
}
map.remove(key);
missCount++;
}
/*
* Attempt to create a value. This may take a long time, and the map may
* be different when create() returns. If a conflicting value was added
* to the map while create() was working, we leave that value in the map
* and release the created value.
*/
V createdReferent = create(context, key);
if (createdReferent == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, new SoftReference<V>(createdReferent));
if (mapValue != null) {
mapReferent = mapValue.get();
}
if (mapValue != null && mapReferent != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdReferent);
}
}
if (mapValue != null && mapReferent != null) {
entryRemoved(false, key, createdReferent, mapReferent);
return mapReferent;
} else {
trimToSize(maxSize);
return createdReferent;
}
}
/**
* Caches {@code value} for {@code key}. The value is moved to the head of
* the queue.
*
* @return the previous value mapped by {@code key}.
*/
public final V put(K key, V referent) {
if (key == null || referent == null) {
throw new NullPointerException("key == null || value == null");
}
SoftReference<V> value = new SoftReference<V>(referent);
SoftReference<V> previousValue;
V previousReferent = null;
synchronized (this) {
putCount++;
size += safeSizeOf(key, referent);
previousValue = map.put(key, value);
if (previousValue != null) {
previousReferent = previousValue.get();
size -= safeSizeOf(key, previousReferent);
}
}
if (previousValue != null) {
entryRemoved(false, key, previousReferent, referent);
}
trimToSize(maxSize);
return previousReferent;
}
/**
* @param maxSize
* the maximum size of the cache before returning. May be -1 to
* evict even 0-sized elements.
*/
private void trimToSize(int maxSize) {
while (true) {
K key;
SoftReference<V> value;
V referent;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
size = 0;
map.clear();
Log.e(LOG_TAG,
getClass().getName()
+ ".sizeOf() is reporting inconsistent results! size: "
+ size + ", maxSize: " + maxSize);
break;
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<K, SoftReference<V>> toEvict = map.entrySet()
.iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
referent = (value != null) ? value.get() : null;
map.remove(key);
size -= safeSizeOf(key, referent);
evictionCount++;
}
entryRemoved(true, key, referent, null);
}
}
/**
* Removes the entry for {@code key} if it exists.
*
* @return the previous value mapped by {@code key}.
*/
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
SoftReference<V> previousValue;
V previousReferent = null;
if (map.containsKey(key)) {
synchronized (this) {
previousValue = map.remove(key);
if (previousValue != null) {
previousReferent = previousValue.get();
size -= safeSizeOf(key, previousReferent);
}
}
if (previousValue != null) {
entryRemoved(false, key, previousReferent, null);
}
}
return previousReferent;
}
/**
* Called for entries that have been evicted or removed. This method is
* invoked when a value is evicted to make space, removed by a call to
* {@link #remove}, or replaced by a call to {@link #put}. The default
* implementation does nothing.
*
* <p>
* The method is called without synchronization: other threads may access
* the cache while this method is executing.
*
* @param evicted
* true if the entry is being removed to make space, false if the
* removal was caused by a {@link #put} or {@link #remove}.
* @param newValue
* the new value for {@code key}, if it exists. If non-null, this
* removal was caused by a {@link #put}. Otherwise it was caused
* by an eviction or a {@link #remove}.
*/
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {
}
/**
* Called after a cache miss to compute a value for the corresponding key.
* Returns the computed value or null if no value can be computed. The
* default implementation returns null.
*
* <p>
* The method is called without synchronization: other threads may access
* the cache while this method is executing.
*
* <p>
* If a value for {@code key} exists in the cache when this method returns,
* the created value will be released with {@link #entryRemoved} and
* discarded. This can occur when multiple threads request the same key at
* the same time (causing multiple values to be created), or when one thread
* calls {@link #put} while another is creating a value for the same key.
*/
protected V create(Context context, K key) {
return null;
}
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "="
+ value);
}
return result;
}
/**
* Returns the size of the entry for {@code key} and {@code value} in
* user-defined units. The default implementation returns 1 so that size is
* the number of entries and max size is the maximum number of entries.
*
* <p>
* An entry's size must not change while it is in the cache.
*/
private final int sizeOf(K key, V value) {
return 1;
}
/**
* Clear the cache, calling {@link #entryRemoved} on each removed entry.
*/
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
/**
* For caches that do not override {@link #sizeOf}, this returns the number
* of entries in the cache. For all other caches, this returns the sum of
* the sizes of the entries in this cache.
*/
public synchronized final int size() {
return size;
}
/**
* For caches that do not override {@link #sizeOf}, this returns the maximum
* number of entries in the cache. For all other caches, this returns the
* maximum sum of the sizes of the entries in this cache.
*/
public synchronized final int maxSize() {
return maxSize;
}
/**
* Returns the number of times {@link #get} returned a value.
*/
public synchronized final int hitCount() {
return hitCount;
}
/**
* Returns the number of times {@link #get} returned null or required a new
* value to be created.
*/
public synchronized final int missCount() {
return missCount;
}
/**
* Returns the number of times {@link #create(Object)} returned a value.
*/
public synchronized final int createCount() {
return createCount;
}
/**
* Returns the number of times {@link #put} was called.
*/
public synchronized final int putCount() {
return putCount;
}
/**
* Returns the number of values that have been evicted.
*/
public synchronized final int evictionCount() {
return evictionCount;
}
@Override
public synchronized final String toString() {
int accesses = hitCount + missCount;
int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
return String
.format("LruCache[size=%d,mapSize=%d,maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
size, map.size(), maxSize, hitCount, missCount,
hitPercent);
}
}
答案 0 :(得分:3)
我遇到了同样的问题。 Recycle()曾经对我的位图繁重的应用程序工作正常但现在似乎没有释放内存,即使我离开它们显示的活动。
我通过在显示位图的所有imageView上保持句柄来解决它,现在当我离开活动时,我不仅回收()位图我还在所有显示的视图上执行setImageBitmap(null)那些位图。
我怀疑使用recycle()来回收内存,即使某些东西仍在引用位图,但它不再那样做了。
答案 1 :(得分:1)
ImageBitmap.recycle()在没有使用imageBitmap的情况下有效 E.G如果你有
mImageView.setImageBitmap(imageBitmap);
mImageView正在使用imageBitmap,因此您需要调用
mImageView.setImageBitmap(null);
发布参考。然后调用
imageBitmap.recycle();
回收imageBitmap
阅读http://developer.android.com/reference/android/graphics/Bitmap.html#recycle%28%29