3

In a listview I want to draw one image on a list entry. These 20 images have to scale to fill the width in vertical mode. The phone resolution is 480 x 800 pixels (SGS2). The images resolution is 400x400 and are about 100KB in size. I've placed the images in the drawable folder.

When I scroll through the list it's not going smooth.

I understand a few things: - application Heap size = limited, Allocated when first run = 13MB, got 1 MB left. - I have GC_FOR_ALLOC Log messages, which halts the system for 15ms. (this is my lagg in scrolling, I think). - After changing the code I also see GC_CONCURRENT messages.

With these GC messages, I understand my garbage-collection kicks in every time I scroll to another image in a new listview entry. This I can analyse so far, but I don't know exactly what to do to fix and remove the GC permanently. I have scaled down the images to 100x100 and it postpones the GC messages for a longer time. But eventually the GC kicks in. I do recycle the views with convertview, and use holders inside the views already.

I've read about re-using image memory, but not sure if and how I do this. Or, maby it's "normal" when using these larger images in a listview and I need to rethink the drawing of the images and only start drawing when the scolling ends?

Should I be using Listview for scrolling through pictures?

2012-12-31_02:11 I've implemented the setOnScrollListener, which makes scrolling smooth. I think this is the piece of code I have to investigate further to butter things up.


listview adapter

public class ListviewAdapter extends BaseAdapter {

    private static Activity activity;
    private int[] data;
    private static LayoutInflater mInflater = null;

    public ListviewAdapter(Activity a, int[] d) {
        activity = a;
        data = d;
        mInflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public int getCount() {
        return data.length;
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listviewitem, parent,
                    false);
            holder = new ViewHolder();

            holder.picture = (ImageView) convertView.findViewById(R.id.image);
            convertView.setTag(holder);

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        if (!MainActivity.isScrolling) {
    holder.picture.setImageResource(data[position]);
    }

        return convertView;
    }

    static class ViewHolder {
        ImageView picture;
    }

}

listview XML

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  <ImageView
      android:id="@+id/image"
      android:src="@drawable/stub"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:contentDescription="Animal images"
        android:scaleType="fitCenter"
        android:scrollingCache="false"
        android:animationCache="false" 
        />

</LinearLayout>
Gaston
  • 307
  • 4
  • 14

2 Answers2

2

You are opening Bitmaps all the time, those take a considerable amount of memory that needs to be collected so that there is space for the awful lot of Bitmaps that you will be loading next.

You could start by using the BitmapFactory Options to subsample the load image if its not going to be displayed at full size. That way, you only take as much memory as needed to fill your view, causing less GC calls.

You could also try keeping some kind of cache inside your adapter, to avoid reloading Bitmaps every time.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Thank you for directing me this way. I'm going to try to solve it and give feedback asap. I've tried to keep the images some bit smaller as my display resolution. Image= 400x400, display = 480 x 800, but still I'm going to find out what memory optimization will take place when resizing the image. – Gaston Dec 29 '12 at 10:39
  • I found out with the BitmapFactory, the resizing of the images was not the problem. So I continue check the caching possibility and "recycling" (not sure if I'm doing this already). – Gaston Dec 30 '12 at 15:14
0

There are lots of techniques to make ListViews faster. See Efficient ListView in android. You should recycle Views, which will decrease Garbage Collection. You might also consider not loading Images before the list scrolling has stopped, see Lazy Load images on Listview in android(Beginner Level)?.

Community
  • 1
  • 1
r-hold
  • 941
  • 8
  • 30
  • I thought with ViewHolders I was recycling views. Or is it the inflater which addresses this? I was reading the Lazy loading of images, but I think this would give me a really lazy solution of which I wouldn't learn this much. Now I'm debugging and learning about the little tweaks, of which others can read and learn again. correct me if I'm wrong. – Gaston Dec 29 '12 at 10:48
  • I believe your point to the OnScrollListener is the part that I needed. As the images are "big" (400x400px) I think I allways get the GC kicked in. – Gaston Dec 31 '12 at 01:18
  • After reading and experimenting I understand there is no such thing as a tool that works for everybody. By experimenting with different pieces of code, Lazy Loading is a great place to start. – Gaston Dec 31 '12 at 15:03