http://blog.csdn.net/w237or45/article/details/7333782 android listview 图片 内存溢出 解决方案

http://www.cnblogs.com/nanguabing/archive/2012/12/09/2810446.html android 大图片在listview中内存溢出的问题

http://www.fengfly.com/plus/view-210860-2.html 大图片在Android的listview中出现内存溢出的解决办法

http://blog.csdn.net/yhb5566/article/details/7741821

http://baquee.blog.163.com/blog/static/164036220123296212861/ Android 内存溢出解决方案

http://blog.chinaunix.net/uid-8210028-id-3574796.html Android工作笔记(六) – 图片内存溢出解决方法

http://download.csdn.net/detail/w237or45/4124069 listview 内存溢出的简单解决方案

 

 

 

在listview中有很多时候,都因为图片太大造成内存溢出的问题,下面这个demo用10M大小的图片测试并没有出现内存溢出和卡顿现象。

项目截图

 

package com.example.listview;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ListView;
 
public class MainActivity extends Activity {
    ListAdapter mAdapter;
    ListView mListView;
    int count = 100;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listView1);
        mAdapter = new ListAdapter(this,mListView);
        mAdapter.setData(count);
        mListView.setAdapter(mAdapter);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
 
}

 

package com.example.listview;
 
import java.util.ArrayList;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
 
public class ListAdapter extends BaseAdapter {
    int mData;
    Context mContext;
    ListView mListView;
    SyncImageLoader mSyncImageLoader;
    ArrayList<String> mlist;
    public ListAdapter(Context context,ListView listView) {
        super();
        this.mContext = context;
        this.mListView=listView;
        this.mListView.setOnScrollListener(onScrollListener);
        mSyncImageLoader=new SyncImageLoader();
        mlist=new ArrayList<String>();
    }
 
    public void setData(int data) {
        this.mData = data;
    }
 
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return mData;
    }
 
    @Override
    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return arg0;
    }
 
    @Override
    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return arg0;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup arg2) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.list_item, null);
            holder.iv01 = (ImageView) convertView.findViewById(R.id.imageView1);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.iv01.setId(0x7f021000+position);
        if(mlist.contains("/sdcard/pic_01.jpg")){
            holder.iv01.setImageBitmap(MyBitmap.readBitMap("/sdcard/pic_01.jpg"+"1.jpg",1));
        }else{
            holder.iv01
            .setImageBitmap(MyBitmap.readBitMap(mContext, R.drawable.load));
            mSyncImageLoader.loadImage(position, "/sdcard/pic_01.jpg", imageLoadListener);
            mlist.add("/sdcard/pic_01.jpg");
        }
        return convertView;
    }
    class ViewHolder {
        public ImageView iv01;
    }
    AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
        }
 
        public void onScrollStateChanged(final AbsListView view, int scrollState) {
            //滑动的三种状态,当滑动停止之后加载图片
            switch (scrollState) {
            case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                System.out.println("SCROLL_STATE_FLING");
                mSyncImageLoader.lock();
                break;
            case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                System.out.println("SCROLL_STATE_IDLE");
                loadImage();
                break;
            case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                System.out.println("SCROLL_STATE_TOUCH_SCROLL");
                mSyncImageLoader.lock();
                break;
            default:
                break;
            }
        }
    };
    private void loadImage(){
        int start = mListView.getFirstVisiblePosition();
        int end = mListView.getLastVisiblePosition();
        if (end >= getCount()) {
            end = getCount() - 1;
        }
        mSyncImageLoader.setLoadLimit(start, end);
        mSyncImageLoader.unlock();
    }
    SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener() {
        public void OnImageLoad(Integer t, Bitmap bitmap) {
            ImageView iv01 =(ImageView) mListView.findViewById(0x7f021000+t);
            if(iv01 !=null){
                iv01.setImageBitmap(bitmap);
            }
        }
    };
}

 

package com.example.listview;
 
import java.util.ArrayList;
 
import android.graphics.Bitmap;
import android.os.Handler;
 
public class SyncImageLoader {
    private Object lock = new Object();
    // 是否允许加载图片
    private boolean mAllowLoad = true;
    // 开始加载图片的位置
    private int mStartLoadLimit = 0;
    // 停止加载图片的位置
    private int mStopLoadLimit = 0;
    ArrayList<String> list=new ArrayList<String>();
    Bitmap mBitmap;
    Handler handler = new Handler();
 
    public interface OnImageLoadListener {
        public void OnImageLoad(Integer id, Bitmap bitmap);
    }
 
    public void setLoadLimit(int startLoadLimit, int stopLoadLimit) {
        mStartLoadLimit = startLoadLimit;
        mStopLoadLimit = stopLoadLimit;
    }
 
    public void lock() {
        mAllowLoad = false;
    }
 
    public void unlock() {
        mAllowLoad = true;
        synchronized (lock) {
            lock.notifyAll();
        }
    }
 
    public void loadImage(Integer t, String imageUrl,
            OnImageLoadListener listener) {
        final OnImageLoadListener mListener = listener;
        final String mImageUrl = imageUrl;
        final Integer mt = t;
        new Thread(new Runnable() {
            public void run() {
                if (!mAllowLoad) {
                    synchronized (lock) {
                        try {
                            lock.wait();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (mStopLoadLimit == 0 && mStartLoadLimit == 0) {
                    loadImage(mImageUrl, mt, mListener);
                }
                if (mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit) {
                    System.out.println("loadImage");
                    loadImage(mImageUrl, mt, mListener);
                }
            }
        }).start();
    }
 
    private void loadImage(final String mImagePath, final Integer mt,
            final OnImageLoadListener mListener) {
        try {
            if(list.contains(mImagePath)){
                mBitmap = MyBitmap.readBitMap(mImagePath + "1.jpg",1);
            }else{
                mBitmap = MyBitmap.readBitMap(mImagePath,20);
                MyBitmap.saveFile(mBitmap, mImagePath + "1.jpg");
                list.add(mImagePath);
            }
            handler.post(new Runnable() {
                public void run() {
                    if (mAllowLoad) {
                        mListener.OnImageLoad(mt, mBitmap);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}
package com.example.listview;
 
import java.io.BufferedOutputStream;
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 android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
 
public class MyBitmap {
    public static Bitmap readBitMap(String fileName,int n) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inSampleSize = n; // width,hight设为原来的十分一
        opt.inPurgeable = true;
        opt.inInputShareable = true; // 获取资源图片
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(fileName);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return BitmapFactory.decodeStream(fis, null, opt);
    }
    public static Bitmap readBitMap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        // opt.inSampleSize = 10; //width,hight设为原来的十分一
        opt.inPurgeable = true;
        opt.inInputShareable = true; // 获取资源图片
        InputStream is = context.getResources().openRawResource(resId);
        return BitmapFactory.decodeStream(is, null, opt);
    }
    public static void saveFile(Bitmap bm, String fileName) throws IOException {
        File myCaptureFile = new File(fileName);
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(myCaptureFile));
        bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
        bos.flush();
        bos.close();
    }
 
}

 

 

http://blog.csdn.net/w237or45/article/details/7333782

刚开始接触android开发的时候 经常会碰到一个问题 就是 listview 里的图片太多 会导致 listview 的OutOfMemoryException发生,

而网上却没有很详细的解决方案,只有例如 软引用 ,手动recycle 资源,缩小bitmap等等。(不过貌似都治标不治本,所以以前这个问题 一直困扰了我很久。。。)

即使使用了这些解决方案 也很可能碰到 以下的几个问题

1. 图片 比如 bitmap 或者 drawable 虽然可以用recycle 方法手动释放,但是 释放的时机。

2. 即使使用手动释放,但由于 图片被 imageview 或者其他控件引用 导致发生异常 比如 trying to use a recycled bitmap

 

package com.testmemoryadapter;
 
import java.util.ArrayList;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
 
public class TestAdapter extends BaseAdapter {
 
	private ArrayList list;
	private LayoutInflater mInflater;
	private Context context;
	//这个用来保存 imageview 的引用
	private ArrayList viewList = new ArrayList();
	//这个用来 保存 bitmap
	private ArrayList bitmapList = new ArrayList();
 
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return list.size();
	}
 
	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}
 
	public TestAdapter(Context context, ArrayList list) {
		super();
		this.context = context;
		this.mInflater = LayoutInflater.from(context);
		this.list = list;
	}
 
	@Override
	public View getView(int position, View convertView, ViewGroup arg2) {
		// TODO Auto-generated method stub
 
		convertView = mInflater.inflate(R.layout.test_list_row, null);
 
		ImageView iv = (ImageView) convertView.findViewById(R.id.imageView);
 
 
		//用try catch 块包围住
		try {
			setImage(iv);
		} catch (OutOfMemoryError e) {
			// 这里就是当内存泄露时 需要做的事情
			e.printStackTrace();
 
			Log.d("memory", "out");
 
			//释放内存资源
			recycleMemory();
 
			//将刚才 发生异常没有执行的 代码 再重新执行一次
			setImage(iv);
 
		}
 
		return convertView;
	}
 
 
	//这里是关键
	private void recycleMemory() {
		//一屏显示多少行 这里就设置为多少。不设也行 主要是用户体验好 不会将用户看到的图片设为默认图片
		int showCount = 10;
 
		//
		for (int i = 0; i < viewList.size()-showCount; i++) {
			ImageView iv = (ImageView) viewList.get(i);
			/***
			 *  这里是关键! 将 imageview 设置一张默认的图片 ,
			 *  用于解决当释放bitmap的时候 还有其他 控件对他保持引用
			 *  就不会发生trying to use a recycled bitmap异常了
			 */
			iv.setImageResource(R.drawable.default_cover);
			//从list中去除
			viewList.remove(i);
		}
 
//		viewList = new ArrayList();
 
		for (int i = 0; i < bitmapList.size()-10; i++) {
 
			Bitmap bitmap = (Bitmap) bitmapList.get(i);
			//这里就开始释放bitmap 所占的内存了
			if (!bitmap.isRecycled()) {
				bitmap.recycle();
				System.out.println("recycle ");
			}
			//从list中去除
			bitmapList.remove(i);
		}
 
//		bitmapList = new ArrayList();
	}
 
	private void setImage(ImageView iv){
		/***
		 * 从sdcard获取 图片  这张图片 只要不超过  android对于图片大小的限制即可 
		 * 我用了 一张比较大的图片 也通过测试
		 */
		Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test/1.jpg");
 
		iv.setImageBitmap(bitmap);
 
		//将这个控件 添加到 list里
		viewList.add(iv);
		//将要 释放的 bitmap也添加到list里
		bitmapList.add(bitmap);
	}
 
}

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="80dip"
        android:layout_height="80dip" android:src="@drawable/default_cover"/>
 
</LinearLayout>

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
 
    <ListView
        android:id="@+id/testListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </ListView>
 
</LinearLayout>

 

package com.testmemoryadapter;
 
import java.util.ArrayList;
 
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
 
public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ArrayList testList = new ArrayList();
 
        for (int i = 0; i < 30; i++) {
			testList.add(0);
		}
 
        TestAdapter ta = new TestAdapter(this,testList);
 
        ListView lv = (ListView) findViewById(R.id.testListView);
 
        lv.setAdapter(ta);
 
    }
}

 

接下来放心大胆的测试吧吗哈哈 ,这个解决方案 虽然并不是很规范 但是基本能解决 内存溢出的问题。我用了500k左右的图片 测试下没问题 还有我的运行版本是2.2。希望能给被这个问题困扰的朋友们提供些思路。

http://download.csdn.net/detail/w237or45/4124069

这里是源码下载的位置

用源码里的图片在普通情况下显示10张就 溢出了 ,用了以下的方法后 测试200张 都没有问题~

 

 

更新日期: 2015-01-26 10:46:32
文章标签:
文章链接: 大图片在Android的Listview中出现内存溢出的解决办法
站方声明: 除特别标注, 本站所有文章均为原创, 互联分享, 尊重版权, 转载请注明.