6

I have a list of 70 text items with image icons(which are stored in drawables folder). If I launch application the first time and scroll the list slowly - the exception doesn't occur.

When the application is launched the first time and I scroll the list with 'fling' action the following exception occurs:

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
 at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
 at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:439)
 at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:322)
 at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:688)
 at android.content.res.Resources.loadDrawable(Resources.java:1710)
 at android.content.res.Resources.getDrawable(Resources.java:585)

After that, if I kill the application with DDMS, start it again and scroll it with 'fling' action, exception doesn't occur. So the exception arises only if application is installed and launched the first time.

Here is the adapter I use for the list:

public class AuthorAdapter extends ArrayAdapter<Author> {

private ArrayList<Author> items;
private Context context;
private LayoutInflater inflater;

public AuthorAdapter(Context context, int textViewResourceId, ArrayList<Author> items) {
    super(context, textViewResourceId, items);
    this.items = items;
    this.context = context;
    inflater = LayoutInflater.from(this.context);
}

static class ViewHolder {
    ImageView authorFace;
    TextView authorName;
    TextView authorWho;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;

    if (convertView == null) {
        convertView = inflater.inflate(R.layout.autor_data, null);

        holder = new ViewHolder();
        holder.authorFace = (ImageView) convertView.findViewById(R.id.authorFaceImageView);
        holder.authorName = (TextView) convertView.findViewById(R.id.authorNameTextView);
        holder.authorWho = (TextView) convertView.findViewById(R.id.authorWhoTextView);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    Author author = items.get(position);
    if (author != null) {
        if (holder.authorFace != null) {
            String faceFileName = author.getFace();
            String facePlaceName = context.getPackageName() + ":drawable/" + faceFileName.subSequence(0, faceFileName.lastIndexOf("."));
            int faceFileId = context.getResources().getIdentifier(facePlaceName, null, null);
            holder.authorFace.setImageResource(faceFileId);
        }
        if (holder.authorName != null) {
            holder.authorName.setText(author.getName());
        }
        if (holder.authorWho != null) {
            holder.authorWho.setText(author.getWho());
        }
    }
    return convertView;
}

}

Is there a way to avoid the exception? Should I catch the exception and escape the memory somehow?

Any advice how to accomplish this?

Thanks.

k_shil
  • 2,108
  • 1
  • 20
  • 25
  • List item images are about 3KB each. I use two activitie(main and list). Activity background images are about 60KB each. Also there are images I use for UI controls, about 100 KB in total. Can it be a simulator problem? Unfortunately I can not try my app on device at the moment. – k_shil Jan 18 '10 at 07:09

1 Answers1

3

You can't catch a java.lang.OutOfMemoryError. They're pretty much fatal.

Now, you say the problem only occurs the first time you run your application. This makes me think that the problem isn't with the view code. If a user flings a resource heavy view it can use a lot of memory, but as you say, normally your application works fine.

So - what initialisation do you do the first time you run your application? Is it possible one of the first-time run-once tasks is leaking memory meaning that there isn't enough left to use your view?

David Webb
  • 190,537
  • 57
  • 313
  • 299
  • Actually I do not initialize any images when I first start the application. All my images are stored in the drawables folder. I only set the adapter for the list. In the getView() method of the adapter I set the image for each list item(see the code above): holder.authorFace.setImageResource(faceFileId); As I understand getView() method is called each time a list item is shown on the phone screen. Probably when I quickly scroll the list the cache doesn't have time to recycle. When I slowly scroll the list no exception is observed. – k_shil Jan 15 '10 at 10:23
  • 2
    I was wondering if there's some other initialisation behaviour that's leaking memory so there's no room on the Heap for lots of images when you fast scroll your View. This would explain why the problem only occurs the first time you run your application. – David Webb Jan 15 '10 at 10:44
  • 1
    Agree with Dave, i'd start to look on what are you doing first time you start the app vs normal startup. You're holding to something big during your first init of the app. – Alex Volovoy Jan 15 '10 at 15:10
  • Thanks for the help. I do use background and button images in the activity that precedу my list activity. Though I initialize them in my xml layout. Do I have to unbind them according to http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html ? Can anyone give a working example on how to deal with heavy images set as activity background? – k_shil Jan 18 '10 at 07:00
  • I am having the same issue, if i want to get the files from the drawable folders. But when i get then by filename out of the assets folder, it does work. // get input stream InputStream ims = null; try { ims = context.getAssets().open(imageFile); } catch (IOException e) { e.printStackTrace(); } // load image as Drawable Drawable d = Drawable.createFromStream(ims, null); // set image to ImageView imageView.setImageDrawable(d);| return rowView; I would realy like to use the drawable directory, for different resolutions. – FuZZbaLL Oct 24 '13 at 09:44