Как решить ошибку кучи памяти бюджета VM в отложенной загрузке растровых изображений? - PullRequest
2 голосов
/ 24 сентября 2011

Я использую класс загрузчика изображений для отложенной загрузки в виде списка. Это прекрасно работает, но я имел дело с большим количеством растровых изображений, которые будут загружены с веб-службы. так что теперь я получаю размер растрового изображения превышает бюджет виртуальной машины. Увеличен размер растрового изображения до 32 * 1024, но если он снова достигнет 32 Мб, он выдаст ошибку. Это ломало мне голову в течение прошлой недели. так что кто-нибудь, пожалуйста, помогите мне выйти из этой проблемы. Я также опубликовал свой класс загрузчика изображений, пожалуйста, дайте мне знать, где и как мне решить эту проблему.

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 ]

1 голос
/ 24 сентября 2011

Проще говоря, вы пытаетесь использовать больше памяти, чем дает виртуальная машина Android. Поэтому вам нужно использовать меньше.

Вы либо:

(1) необходимо вручную очистить кэш в памяти, т. Е. Как только вы достигнете определенного размера или количества изображений

или альтернативно

(2) используйте HashMap типа <String, SoftReference<Bitmap>>, чтобы сборщик мусора мог автоматически восстанавливать память, когда изображения больше не отображаются.

При использовании любого из этих методов кэш-память в памяти не должна становиться такой же большой, как раньше (и это хорошо), поэтому вы можете сохранить свои файлы на диск, чтобы их не нужно было загружать снова, если их очистить кэш в памяти.

0 голосов
/ 27 сентября 2011

проверьте по ссылкам ниже ... мы можем понять это ...

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

0 голосов
/ 27 сентября 2011

Попробуй вот так ..

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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...