In an attempt at reducing total heap size of my app I was trying to change a TableLayout into a ListView.
The source list is an ArrayList which items containing a drawble, a text and a checkbox state. This array is entirely initialized beforehand.
Before opening the activity using either the ListView or TableLayout, heap size is about 7.5Mb
With the TableLayout it grows to 8.3Mb and doesn't grow higher With the ListView it grows to 8.1Mb initially and grows to 11.5Mb when scrolling through the list!
Why is the ListView consuming more when scrolling whereas it's supposed to reuse views? I was expecting that ListView will consume less and actually not grow when scrolling!?
Is the behavior I'm seeing normal or expected or am I missing something?
I've verified the ListAdapter does reuse views, here is an extract of the ListAdapter code. It contains the only new() in the getView() method.
private static class AppListAdapter implements ListAdapter
{
WeakReference<MyActivity> wr;
ArrayList<AppInfo> app_list;
public AppListAdapter(MyActivity activity, ArrayList<AppInfo> list)
{
wr = new WeakReference<at_startup_apps>(activity);
app_list = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
MyActivity activity = wr.get();
if (sa == null)
return null;
AppInfo ai = app_list.get(position);
LinearLayout ll;
ImageView img;
TextView new_txt;
CheckBox cb;
if (convertView == null)
{
ll = new LinearLayout(activity);
img = new ImageView(sa);
img.setScaleType(ScaleType.FIT_CENTER);
ll.addView(img);
new_txt = new TextView(activity);
new_txt.setOnClickListener(activity.onTextClick);
new_txt.setGravity(Gravity.CENTER_VERTICAL);
new_txt.setPadding(4, 2, 4, 2);
new_txt.setTextSize(activity.font_size + 2);
ll.addView(new_txt);
cb = new CheckBox(sa);
ll.addView(cb);
}
else
{
Log.d(at_data.TAG, "Reusing view " + position);
ll = (LinearLayout)convertView;
img = (ImageView)ll.getChildAt(0);
new_txt = (TextView)ll.getChildAt(1);
cb = (CheckBox)ll.getChildAt(2);
}
ll.setId(position);
img.setImageDrawable(ai.drawable);
new_txt.setText(ai.name);
new_txt.setId(position);
cb.setOnCheckedChangeListener(null);
if (!ai.frozen)
cb.setChecked(true);
cb.setOnCheckedChangeListener(sa.onCheckedListener);
cb.setId(position);
return ll;
}
So i decided to test the behavior on 5 test devices, each tests were performed twice to ensure results accuracy.
From the results I'd say ListView improves performance and memory consumption only if enough items are to be displayed. With 300 or less it seemed not very useful for any improvements.
Beyond that the gain is immediately visible, both in term of performance and consumption.
The Iconia A500 is the only device on which the ListView consumed more when scrolling. Not sure why, but any results are reassuring ;)
On the Nexus ListView didn't seem to be effective, but couldn't redo the tests or test with more items.
On the S3, not sure what's going on either but apps are definitely consuming a lot for nothing!
All this doesn't solve my initial problem: saving heap memory space, while my lists rarely grows higher than 300 (all apps installed).
Tested HW acceleration on/off, no difference in results.
Iconia A500 4.0.3: list contains 180 items
TF700 4.0.3: list contains 160 items
Galaxy S3 JB 4.1: list contains 365 items
Galaxy Nexus JB 4.1: list contains 185 items
Galaxy S 2.3.6: list contains 205 items
Some tests with 10 times more items Obviously TableLayout is very slow to initialize: a few seconds!
Galaxy S 2.3.6: list contains 2050 items
Galaxy S3 JB 4.1: list contains 3650 items
Iconia A500 4.0.3: list contains 1800 items