0

I have a ListView with a custom ArrayAdapter, and according to documentation and what I read everywhere, getView() gets called when creating new view (In this case list item) or recycling an old view (convertView),or at least this is what I understood.

Anyway, on my mobile (Note 3 Kitkat), I have a listView that preview at most in the loading mode (The log is below) 3 list items (Visually 2.2 items), of course I can scroll up / down to show full 2 items + 0.2 from the other 2 items (Which means my listView at most will preview 4 list items).

When I set to have a log, getView() is being called 6 times, first time convertView is NULL and followed by 3 times is "NOT null", followed by 2 times "Is Null".

01-21 20:11:22.758  11517-11517/www.test.ar D//*/*/ convertView﹕ IS Null - Position is: 0
01-21 20:11:22.903  11517-11517/www.test.ar D//*/*/ convertView﹕ Not Null - Position is: 1
01-21 20:11:22.913  11517-11517/www.test.ar D//*/*/ convertView﹕ Not Null - Position is: 2
01-21 20:11:22.943  11517-11517/www.test.ar D//*/*/ convertView﹕ Not Null - Position is: 0
01-21 20:11:22.963  11517-11517/www.test.ar D//*/*/ convertView﹕ IS Null - Position is: 1
01-21 20:11:23.028  11517-11517/www.test.ar D//*/*/ convertView﹕ IS Null - Position is: 2

So, shouldn't convertView be NULL as long as there is no scrolling down / up, in other words as long as there are no view going out of screen scope?!

In such case as mine, how many items the ArrayAdapter should create at first loading, 3 items or 4 items?

The code I use:

public class MyListArrayAdapter extends ArrayAdapter<String>
{
    public MyListArrayAdapter (Context context, String[] aTitles,  String[] aImagesURL)
{
        super(context, R.layout.list_item, aTitles);
}

   @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
       if(convertView == null)
        {
            Log.d("/*/*/ convertView", "IS Null - Position is: " + position);

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.list_item, parent, false);
        }
        else
        {
            Log.d("/*/*/ convertView", "Not Null - Position is: " + position);
        }
    }
}

list_item.xml

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="200dp"
    android:orientation="horizontal" >

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/background_with_shadow">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true">

    <!-- title -->
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="8dp"
        android:textSize="18sp"
        android:maxLength="50"
        android:maxLines="1"
        android:text="Default Text"/>


    <!-- icon -->
    <ImageView
        android:id="@+id/icon"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:layout_below="@+id/title"
        android:src="@drawable/default_pic"/>

        </RelativeLayout>

</RelativeLayout>

</FrameLayout>

background_with_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item >
        <shape
            android:shape="rectangle">
            <solid android:color="#DCDCDC" />
            <corners android:radius="2dp"/>
        </shape>
    </item>

    <item android:right="0.5dp" android:left="0.5dp" android:top="0.0dp" android:bottom="1.0dp">
        <shape
            android:shape="rectangle">

            <corners android:radius="2dp"/>
            <padding android:left="7dp" android:right="7dp" android:top="7dp" android:bottom="7dp" />
            <solid android:color="#FFFFFF" />
        </shape>
    </item>

</layer-list>
Ashraf Alshahawy
  • 1,139
  • 1
  • 14
  • 38
  • Where is this code you speak of? – Jared Burrows Jan 21 '15 at 17:47
  • @JaredBurrows Please recheck the question, I added the code, thank you. – Ashraf Alshahawy Jan 21 '15 at 18:00
  • Add your list_item.xml – Simas Jan 21 '15 at 18:01
  • Check (log) the `position` parameter along with the `convertView` to provide better context of what is happening. It could be that the `ListView` is pre-caching views then refreshing them as it is being laid out, etc. – Larry Schiefer Jan 21 '15 at 18:03
  • @user3249477 Done, added the list_item.xml file – Ashraf Alshahawy Jan 21 '15 at 18:18
  • @LarrySchiefer Done, please recheck the modified log in my question. – Ashraf Alshahawy Jan 21 '15 at 18:18
  • @user3249477 is spot on in the answer. The log verifies this: the `ListView` is pulling `View` objects for items in the list as it figures out how to lay them out. – Larry Schiefer Jan 21 '15 at 18:25
  • @LarrySchiefer OK, somehow it makes since, First item must be null so the user inflate it under "if(convertView == null)" and the followed 2 items are being sent as "!=null" to avoid inflating them and the adapter already has the layout measures from the first item .... Then it resend the convertView as != null for the first item (to avoid inflating it again), and null for the other 2 so I inflate them in my code. – Ashraf Alshahawy Jan 21 '15 at 18:34

1 Answers1

2

The first time your ListView is shown, it will call getView multiple times to fetch and measure views that fit on the screen.

You should only be worried if you keep seeing convertView: IS Null while scrolling the list.

A similar question has been answered quite a while ago by one of Google employees. I also strongly suggest watching a video about ListView performance.

Community
  • 1
  • 1
Simas
  • 43,548
  • 10
  • 88
  • 116
  • Thank you, but if I want to set the tag of the convertView to hold the position (I'm going to use AsyncTask to download images and set them to the related list item), do I do it in (==null) or in (!=null)? .... I'm setting the covertView tag with position so I can compare the position hold by the AsyncTask object against the current position of the related view. – Ashraf Alshahawy Jan 21 '15 at 18:38
  • @Astrount it should be called in `getView`. Inside of (==null) you inflate and set tag. Inside of (!=null) you get tag and elements. Outside of (and after) everything you do your every-item-work, e.g. fetch and set images. – Simas Jan 21 '15 at 18:41
  • Again thank you :) I modified my ListView layout_height to be "fill_parent" rather than "match_parent" (according to the first link you provided) and the repetition of calling getView as in my question is vanished, now it's being called with convertView as I expect [null, null, null] and only for 3 times. – Ashraf Alshahawy Jan 21 '15 at 20:06