Getting an exception OutofMemoryError

2020-05-09 17:04发布

问题:

I have someone getting an error while loading a bunch of images on my app and I'm not sure whats causing it.

This is the error he gets. LINE 135 is at the bottom.
I'm thinking he is running out of memory on his phone. He is using a Desire HD which was made in 2010. What this method does is get an image from the server and keep it in a hash map. Along with displaying it onto the screen. Any ideas on how I could prevent this OUTMEMORYERROR?

I was thinking setting up a counter that just clears the hash map if there are over 20 images.

Logcat:

java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
at com.codalata.craigslistchecker.GETTHEIMAGE$ITask.doInBackground(GETTHEIMAGE.java:135)
at com.codalata.craigslistchecker.GETTHEIMAGE$ITask.doInBackground(GETTHEIMAGE.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:185)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)

Code:

 public class GETTHEIMAGE {

private HashMap<String, Drawable> ICache;
private static Drawable DefIcon = null;
private BaseAdapter adapt;
private ItemView item;
private int num = 0;

public GETTHEIMAGE(Context c) {
    ICache = new HashMap<String, Drawable>();
}

public Drawable GetTheImagedata(
        com.codalata.craigslistchecker.Favorites.TheListAdapter theListAdapter,
        ImageView ICON_IMG) {
    this.adapt = theListAdapter;
    String url = (String) ICON_IMG.getTag();
    if (ICache.containsKey(url)) {
        return ICache.get(url);
    } else {
        new ITask().execute(url);
        return DefIcon;
    }
}

public Drawable GetTheImagedata(TheListAdapter adapter, ImageView ICON_IMG) {
    this.adapt = adapter;
    String url = (String) ICON_IMG.getTag();
    if (ICache.containsKey(url)) {
        return ICache.get(url);
    } else {
        new ITask().execute(url);
        return DefIcon;
    }
}

public Drawable GetTheImagedata2(ItemView itemView, String string) {
    this.item = itemView;
    String url = string;
    if (ICache.containsKey(url)) {
        return ICache.get(url);
    } else {
        new ITask2().execute(url);
        return DefIcon;
    }
}

private class ITask2 extends AsyncTask<String, Void, Drawable> {
    private String Nick;

    @Override
    protected Drawable doInBackground(String... params) {
        Nick = params[0];
        InputStream isImage = null;
        try {
            URL url = new URL(Nick);
            isImage = url.openStream();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Drawable.createFromStream(isImage, "Nick");
    }

    @Override
    protected void onPostExecute(Drawable result) {
        super.onPostExecute(result);
        if (num == 0) {
            item.ivItemimage1.setImageDrawable(result);
        }
        if (num == 1) {
            item.ivItemimage2.setImageDrawable(result);
        }
        if (num == 2) {
            item.ivItemimage3.setImageDrawable(result);
        }
        if (num == 3) {
            item.ivItemimage4.setImageDrawable(result);
        }
        if (num == 4) {
            item.ivItemimage5.setImageDrawable(result);
        }
        if (num == 5) {
            item.ivItemimage6.setImageDrawable(result);
        }
        if (num == 6) {
            item.ivItemimage7.setImageDrawable(result);
        }
        if (num == 7) {
            item.ivItemimage8.setImageDrawable(result);
        }
        if (num == 8) {
            item.ivItemimage9.setImageDrawable(result);
        }
        if (num == 9) {
            item.ivItemimage10.setImageDrawable(result);
        }
        num++;
    }
}

private class ITask extends AsyncTask<String, Void, Drawable> {
    private String Nick;

    @Override
    protected Drawable doInBackground(String... params) {
        Nick = params[0];
        InputStream isImage = null;
        try {
            URL url = new URL(Nick);
            isImage = url.openStream();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try{
 LINE 135 ----->            return Drawable.createFromStream(isImage, "Nick");
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Drawable result) {
        super.onPostExecute(result);
        synchronized (this) {
            ICache.put(Nick, result);
        }
        adapt.notifyDataSetChanged();
    }
}
 }

回答1:

You need to scale down the bitmaps and load a scaled down version in memory.

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Use appropriateBitmapFactory.decode method as needed.

Here's an Example:

Out of Memory error with Bitmap

Note: As of Android 3.0 (API Level 11), the pixel data is stored on the Dalvik heap along with the associated bitmap.

On Android 2.3.3 (API level 10) and lower, using recycle() is recommended. If you're displaying large amounts of bitmap data in your app, you're likely to run into OutOfMemoryError errors. The recycle() method allows an app to reclaim memory as soon as possible.

Android 3.0 (API Level 11) introduces theBitmapFactory.Options.inBitmap field. If this option is set, decode methods that take the Options object will attempt to reuse an existing bitmap when loading content. This means that the bitmap's memory is reused, resulting in improved performance, and removing both memory allocation and de-allocation.

http://developer.android.com/training/displaying-bitmaps/manage-memory.html



回答2:

in your first AsyncTask class num++; always increasing, so at some value it goes beyond memory space allocated for this program, you should put a control for that