0

I have a ListView and a GridView both causing me problems and OutOfMemory errors when scrolling, I read online about the issue and saw this question so I used Sunil's first solution and implemented it in my code. the images for the GridView and ListView are at "/res/drawable/image1.png" and so on, I passed to the CustomAdapter class this int array public static int[] mDrawableImg = {R.drawable.back, R.drawable.arrows, R.drawable.bomber, R.drawable.archers, R.drawable.knight}; and used this:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    final Holder holder = new Holder();
    final View rowView = inflater.inflate(R.layout.program_list2, null);
    holder.img = (ImageView) rowView.findViewById(R.id.imageView1);
      holder.img.setImageResource(imageId[position]);
  //  holder.img.setImageBitmap(convertBitmap(String.valueOf(imageId[position])));
            return rowView;
}

Now as you see I added a line of code to load the image from Bitmap with a function called convertBitmap but my GridView is empty, its scrollable meaning there are items but the images are not loaded.

convertBitmap Function:

public static Bitmap convertBitmap(String path) {
    Bitmap bitmap = null;
    BitmapFactory.Options bfOptions = new BitmapFactory.Options();
    bfOptions.inDither = false;
    bfOptions.inTempStorage = new byte[32 * 1024];
    File file = new File(path);
    FileInputStream fs = null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    try {
        if (fs != null) {
            bitmap = BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fs != null) {
            try {
                fs.close();
            } catch (IOException e) {

                e.printStackTrace();
            }
        }
    }
    return bitmap;
}

What have I done wrong and will it solve my OutOfMemory errors? thanks.

Community
  • 1
  • 1
DAVIDBALAS1
  • 484
  • 10
  • 31

1 Answers1

1

The error you get is absolutely logical. Look at this line in your getView() method:

final View rowView = inflater.inflate(R.layout.program_list2, null);

What does it mean? It means that you're creating a new instance of the item each time Android requests you a View for it. That's pretty insane, because you just create and create more views while you scroll the ListView (so is pretty natural that you get an out of memory error. And I'm sure your ListView is scrolling laggy).

And I bet Android Studio is warning you this issue by remarking that line in yellow color.

Affortunately, you can fix it very easily. But let me say you some things. Look at the View that you're receiving in the getView() method as a parameter. Don't you see it? Is the variable that you called convertView. And note that you're not using it. What is this View? Is called a recycled view (Not to be confused with RecyclerView class). Is a view that was previously inflated and no longer used because is not visible for the user. And this, my friend, this is the key of your problem and also of your solution: Instead of inflate one new view each time, just recycle it. I promise you is very simple. Now your getView methos should look like this:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null)
        convertView = inflater.inflate(R.layout.program_list2, null);

    //final Holder holder = new Holder();
    //holder.img = (ImageView) convertView.findViewById(R.id.imageView1);
    //holder.img.setImageResource(imageId[position]);


    ImageView img = (ImageView) convertView.findViewById(R.id.imageView1);
    //Note you don't need the Holder
    Bitmap imageBitmap = convertBitmap(imageId[position]);
    if (imageBitmap != null)
        img.setImageBitmap(imageBitmap);
    else
        img.setImageBitmap(null);

    return convertView;
}

And please look at your usage of the ViewHolder pattern. You're using it wrong...

Joaquin Iurchuk
  • 5,499
  • 2
  • 48
  • 64
  • You are returning the rowView but it doesn't exist, what should I do with it? – DAVIDBALAS1 Jun 18 '16 at 21:58
  • @DAVIDBALAS1Oh, my mistake. Look at the edited answer. You should use the same convertView – Joaquin Iurchuk Jun 18 '16 at 22:01
  • @DAVIDBALAS1 Yes, you're doing Bitmap inflation in the main thread. And you're not caching Bitmaps. You should lay off those tasks to other threads... Or at least cache them using LruCache. Google for it... And, also, review your ViewHolder... Is misused here. It has no impact on the performance... You create a Holder, you assign it an image and then you're done with it and you return a View? The Holder is created and never used. (I wouldn't like to think that you're using it as a variable class...). Look at my new edit... – Joaquin Iurchuk Jun 18 '16 at 22:09
  • Thanks, it's a bit complicated but anyway, even if I am doing the Bitmap inflation in the main thread, it still should work but ineffectively isn't it? it doesn't show me nothing – DAVIDBALAS1 Jun 18 '16 at 22:16
  • @DAVIDBALAS1 Yes, but first be sure that `imageId[position]` is not returning you null... Look at my new edit and let me know if that actually works... – Joaquin Iurchuk Jun 18 '16 at 22:20
  • What are you storing on the imageId array? – Joaquin Iurchuk Jun 18 '16 at 22:22
  • I used your code and it's now successfully load all the grid with imagebitmaps but strangely, it shows on every item the first image in imageId array.. – DAVIDBALAS1 Jun 18 '16 at 22:53
  • nope, now it's empty, if it matters you can't use: Bitmap imageBitmap = convertBitmap(imageId[position]); as it requires a String so maybe Bitmap imageBitmap = convertBitmap(String.valueOf(imageId[position])); but still nope.. – DAVIDBALAS1 Jun 18 '16 at 23:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115023/discussion-between-joaquin-and-davidbalas1). – Joaquin Iurchuk Jun 18 '16 at 23:57