如何解决延迟加载位图中的vm预算内存堆错误?

时间:2011-09-24 10:04:03

标签: android android-image

我一直在列表视图中使用Image loader类进行延迟加载。它工作正常,但我一直在处理将从Web服务下载的大量位图。所以现在我得到位图大小超过VM预算。将bitmapfactory大小增加到32 * 1024,但如果它再次达到32mb,则会抛出错误。过去一周它一直在打破我的脑袋。所以有人请帮我解决这个问题。我在这里发布了我的图像加载器类,请让我知道在哪里以及如何解决这个问题。

public class ImageLoader {

private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
Bitmap bitmap = null;

private Activity activity;
PhotosLoader photoLoaderThread=new PhotosLoader();
public ImageLoader(Activity activity){
    this.activity = activity;
    photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
    clearCache();
}
public void DisplayImage(String url, Activity activity, ImageView imageView, String[] imageUrl){
    this.activity = activity;
    if(cache.containsKey(url)){
        imageView.setImageBitmap(cache.get(url));

    }
else{
        imageView.setImageResource(R.drawable.icon);
        queuePhoto(url, activity, imageView);
    }    

}

private void queuePhoto(String url, Activity activity, ImageView imageView){
    this.activity = activity;
    photosQueue.Clean(imageView);
    PhotoToLoad p=new PhotoToLoad(url, imageView);
    synchronized(photosQueue.photosToLoad){
        photosQueue.photosToLoad.push(p);
        photosQueue.photosToLoad.notifyAll();
    }
    if(photoLoaderThread.getState()==Thread.State.NEW)
        photoLoaderThread.start();
}

public Bitmap getBitmap(String url, int sampleSize) throws Exception{
    Bitmap bm = null;
    try {
        URL request = new URL(url);
        InputStream is = (InputStream) request.getContent();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inDither = true;
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inSampleSize = sampleSize;
        options.inTempStorage = new byte[32 * 1024];

        bm = BitmapFactory.decodeStream(is, null, options);
        if (bm!=null)
        bm = Bitmap.createScaledBitmap(bm, 115,100, true);
        is.close();
        is = null;
    } catch (IOException e) {
        throw new Exception();
    } catch (OutOfMemoryError e) {
        bm.recycle();
        bm = null;
        System.gc();
        throw new Exception();
    }
    return bm;
}
private class PhotoToLoad{
    public String url;
    public ImageView imageView;
    public PhotoToLoad(String u, ImageView i){
        url=u; 
        imageView=i;
    }
}
PhotosQueue photosQueue=new PhotosQueue();
public void stopThread(){
    photoLoaderThread.interrupt();
}
static class  PhotosQueue{
    private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
    public void Clean(ImageView image){
        for(int j=0 ;j<photosToLoad.size();){
            try{
            if(photosToLoad.get(j).imageView==image)
                photosToLoad.remove(j);
            else
                ++j;
            }catch (Exception e) {
            }
        }
    }
}
class PhotosLoader extends Thread {
    public void run() {
        try {
            while(true){

                if(photosQueue.photosToLoad.size()==0)
                    synchronized(photosQueue.photosToLoad){
                        photosQueue.photosToLoad.wait();
                    }
                if(photosQueue.photosToLoad.size()!=0){
                    PhotoToLoad photoToLoad;
                    synchronized(photosQueue.photosToLoad){
                        photoToLoad=photosQueue.photosToLoad.pop();
                    }
                    Bitmap bmp = null;
                        bmp = getBitmap(photoToLoad.url, 1);
                    cache.put(photoToLoad.url, bmp);
                    if(((String)photoToLoad.imageView.getTag()).equals(photoToLoad.url)){
                        BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView);
                        Activity a=(Activity)photoToLoad.imageView.getContext();
                        a.runOnUiThread(bd);
                    }
                }
                if(Thread.interrupted())
                    break;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


class BitmapDisplayer implements Runnable{
    ImageView imageView;
    public  BitmapDisplayer(Bitmap b, ImageView i){
        bitmap = null;
        bitmap=b;
        imageView=i;
        }
    public void run(){
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
            imageView.setScaleType(ScaleType.FIT_XY);
        }
        else{
            imageView.setImageResource(R.drawable.icon);
        }
    }
}

public void clearCache() {
    try{
    cache.clear();
    cache = new HashMap<String, Bitmap>();
    bitmap.recycle();   
    System.gc();
    }catch (Exception e) {
    }
}

3 个答案:

答案 0 :(得分:1)

很简单,您尝试使用比Android VM更多的内存。所以你需要少用。

你要么:

(1)需要手动清除内存缓存 - 即一旦达到一定大小或数量的图像

或者

(2)使用类型为<String, SoftReference<Bitmap>>的HashMap,以便垃圾收集器可以在不再显示图像时自动回收内存。

使用这些方法中的任何一种,您的内存缓存都不应该像以前一样大(这很好),因此您可能希望将文件保存到磁盘,以便在从中清除文件时不必再次下载它们内存缓存。

答案 1 :(得分:0)

试试这样..

try {
    HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
    conn.setDoInput(true);
    conn.connect();
    int length = conn.getContentLength();
    InputStream is = conn.getInputStream();

    bmImg = BitmapFactory.decodeStream(is);
    proImage.setImageBitmap(bmImg); // Bind image here on UI thread

    clearBitMap(bmImg); // Call to clear cache 
} 
catch (IOException e) {
    e.printStackTrace();
}


private void clearBitMap(Bitmap bitMap) {
    bitMap = null;
    System.gc();
}

答案 2 :(得分:0)

验证以下链接......我可以了解这个......

http://negativeprobability.blogspot.com/2011/08/lazy-loading-of-images-in-listview.html http://stackoverflow.com/questions/5082703/android-out-of-memory-error-with-lazy-load-images http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/ http://groups.google.com/group/android-developers/browse_thread/thread/bb3c57cab27e0d91?fwc=1