项目中用到大量大图,造成快速切换Activity后内存不足,如登录界面用到3M高清大图,设备选择用到5张大图背景叠加效果,主界面用到了5张遮罩大图,设置界面总的子activity中也有大图出现。
启动Splash——设备选择界面(保留栈低,不finish,但会把背景图片回收)-->主界面--->设置界面-->设置子界面(有大图背景\或者WebView(WebView内存泄漏 https://www.jianshu.com/p/3e8f7dbb0dc7)
通过跟踪调试发现,在快速返回过程中,activity没有及时调用ondestry,这就会出现图片内存没有得到释放,而此时已经返回到了设备选择界面,开启加载设备选择界面的大图背景。问题发现了百度了ImageView 释放的内存的关键字,发现前篇一律的方式都是bitmap的回收方法,但在实际中被并没有达到效果。
最后通过查看android 内存管理机制,以及andorid 弱引用和软引用得到了启发。
当我们直接在xml中ImageView设置了背景图片和src时候,view中(长期持有 Context 的引用()个人理解),这样就会出现activity解释被finish掉了,但它所占用的内存没有得到释放,这样imageview中的 bitmap内存依然占用着。
软引用 和 弱引用 (引用自https://www.cnblogs.com/zhaoyanjun/p/5977190.html)
1. SoftReference<T>:软引用-->当虚拟机内存不足时,将会回收它指向的对象;需要获取对象时,可以调用get方法。
2. WeakReference<T>:弱引用-->随时可能会被垃圾回收器回收,不一定要等到虚拟机内存不足时才强制回收。要获取对象时,同样可以调用get方法。
3. WeakReference一般用来防止内存泄漏,要保证内存被虚拟机回收,SoftReference多用作来实现缓存机制(cache);
最后参考ImageLoader 写了一个demo
package com.example.zdyl;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.Log;
public class MemoryCache {
//Bitmap 用WeakReference<T>:弱引用-->在系统gc 过程中随时可能会被垃圾回收器回收
private static final String TAG = "MemoryCache";
//bitmap 管理集合
private Map<String, WeakReference<Bitmap>> cache = new LinkedHashMap<String, WeakReference<Bitmap>>();// private Map<String, Bitmap> cache=Collections.synchronizedMap(
// new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
}
//将bitmap丢入集合
public void put(String id, WeakReference<Bitmap> bitmap){
try{
cache.put(id, bitmap);
}catch(Throwable th){
th.printStackTrace();
}
}
public void clear() {
try{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
Iterator<Entry<String, WeakReference<Bitmap>>> iter= cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, WeakReference<Bitmap>> entry = iter.next();
WeakReference<Bitmap> tmp = entry.getValue();
if(tmp!=null ){
Bitmap bitmap = tmp.get();
if(bitmap!=null && !bitmap.isRecycled()){
bitmap.recycle();
}
tmp = null;
bitmap =null;
}
}
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
//移除,释放指定bitmap
public void removeCache(int id) {
WeakReference<Bitmap> tmp = cache.get(""+id);
//系统gc可能已经将bitmap 内存释放了,需要判断null
if(tmp!=null ){
Bitmap bitmap = tmp.get();if(bitmap!=null && !bitmap.isRecycled()){
bitmap.recycle();
}
cache.remove(tmp);
tmp = null;
bitmap =null;
}
}
}
package com.example.zdyl; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.os.Handler; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView;
//读取res中的bitmap 设置到wiew中 public class ImageLoader {
static MemoryCache memoryCache=new MemoryCache();
public static boolean isFirst;
public ImageLoader(Context context){
}
public static void decode(Resources context,int id,View view){
Bitmap bmp=BitmapFactory.decodeResource(context, id);
if(view instanceof ImageView){
((ImageView) view).setImageBitmap(bmp);
}else{
view.setBackground(new BitmapDrawable(bmp));
}
// 软引用的Bitmap对象,这样系统会在gc过程中回收掉bitmap,直接使用强引用对象的话,即使调用了bitmap的回收函数 //但是imageview 中bitmap在gc的时候跟随了activity的内存,如果activity因为context对象的长期被引用,那么bitmap的内存就得不到销毁WeakReference<Bitmap> softBitmap = new WeakReference<Bitmap>(bmp);
// 添加该对象到Map中使其缓存
memoryCache.put(""+view.getId(),softBitmap );
bmp = null;
}
public static void removeCache(int id){
memoryCache.removeCache(id);
}
public static void clearCache() {
memoryCache.clear();
}
}
package com.example.zdyl;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
private RelativeLayout t;
private ImageView t1;
private ImageView t2;
private ImageView t3;
private ImageView t4;
private ImageView t5,t6,t7,t8,t9;
private MemoryCache mMemoryCache=new MemoryCache();
private List<View> views = new ArrayList<View>();
//由于图片用的是公司项目中的图片,这里就不提供了,见谅,可以找帧动画中图片资源来代替。
private int[] icons ={iconframe_001,iconframe_002,
iconframe_005,iconframe_006,
iconframe_007,iconframe_008,
iconframe_009,iconframe_010};
private ImageLoader loader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = (RelativeLayout)findViewById(R.id.t0);
t1 = (ImageView)findViewById(R.id.t1);
t2 = (ImageView)findViewById(R.id.t2);
t3 = (ImageView)findViewById(R.id.t3);
t4 = (ImageView)findViewById(R.id.t4);
t5 = (ImageView)findViewById(R.id.t5);
t6 = (ImageView)findViewById(R.id.t6);
t7 = (ImageView)findViewById(R.id.t7);
t8 = (ImageView)findViewById(R.id.t8);
t9 = (ImageView)findViewById(R.id.t9);
views.add(t);
views.add(t1);
views.add(t2);
views.add(t3);
views.add(t4);
views.add(t5);
views.add(t6);
views.add(t7);
views.add(t8);
views.add(t9);
loader = new ImageLoader(this);
//因为要管理bitmap对象,所以没有使用xml中直接设置背景和src
for(int i=0;i<views.size();i++){
loader.decode(this.getResources(), icons[i], views.get(i));}
}
public void d(){
//loader.clearCache();
for (int i = 0; i < views.size(); i++) {
View view = views.get(i);
if (view instanceof ImageView) {
((ImageView) view).setImageBitmap(null);
} else {
view.setBackground(null);
}
ImageLoader.removeCache(view.getId());
}
views.clear();
}
public void onClear(View v){
}
public void onClearc(View v) {
if(this.isFinishing()){
return;
}
Intent i = new Intent(MainActivity.this,MainActivity2.class);
startActivity(i);
if(!ImageLoader.isFirst){
ImageLoader.isFirst = true;
return;
}
finish();
}
@Override
public void finish() {
super.finish();
d();
}
}
demo传输门(只包含as项目src 部分,):https://download.csdn.net/download/zdy10326621/10496926