2

I'm attempting to create a ListView adapter that has multiple types of views. I'm following the following tutorial:

http://android.amberfog.com/?p=296

However, after the first round of building the following code:

public class MultipleItemList extends Activity
{
  private MyCustomAdapter mAdapter;
  private ListView        mListView;
  private String          mTag = "MultipleItemList";

  @Override
  protected void onCreate( Bundle savedInstanceState )
  {
    super.onCreate( savedInstanceState );

    setContentView( R.layout.main );

    mListView = (ListView)findViewById( R.id.main_list );

    mAdapter = new MyCustomAdapter();

    for( int i = 0; i < 50; i++ )
    {
      mAdapter.addItem( "Item: " + i );
    }

    mListView.setAdapter( mAdapter );
  }

  private class MyCustomAdapter extends BaseAdapter
  {
    private ArrayList<String> mData = new ArrayList<String>();
    private LayoutInflater    mInflater;

    public MyCustomAdapter()
    {
      mInflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE );
    }

    public void addItem( final String item )
    {
      mData.add( item );
      notifyDataSetChanged();
    }

    public int getCount()
    {
      return mData.size();
    }

    public String getItem( int position )
    {
      return mData.get( position );
    }

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

    public View getView( int position, View convertView, ViewGroup parent )
    {
      Log.e( mTag, "getView: " + position + " " + convertView );

      ViewHolder holder = null;

      if( convertView == null )
      {
        convertView = mInflater.inflate( R.layout.list_item, null );

        holder = new ViewHolder();

        holder.textView = (TextView)convertView.findViewById( R.id.item_text );

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

      holder.textView.setText( mData.get( position ) );

      return convertView;
    }
  }

  public static class ViewHolder
  {
    public TextView textView;
  }

}

Where the main.xml is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/main_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

And the list_item.xml is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/item_text"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:text="TextView" 
        android:gravity="center_vertical" 
        android:paddingLeft="25dp"/>

</LinearLayout>

I'd expect the output to be similar to his expected output:

02-05 13:47:32.559: INFO/System.out(947): getView 0 null
02-05 13:47:32.570: INFO/System.out(947): getView 1 null
02-05 13:47:32.589: INFO/System.out(947): getView 2 null
02-05 13:47:32.599: INFO/System.out(947): getView 3 null
02-05 13:47:32.619: INFO/System.out(947): getView 4 null
02-05 13:47:32.629: INFO/System.out(947): getView 5 null
02-05 13:47:32.708: INFO/System.out(947): getView 6 null
02-05 13:47:32.719: INFO/System.out(947): getView 7 null
02-05 13:47:32.729: INFO/System.out(947): getView 8 null

But instead, with no user interaction, just loading the screen, I'm getting the following:

05-09 15:24:00.347: E/MultipleItemList(11109): getView: 0 null
05-09 15:24:00.357: E/MultipleItemList(11109): getView: 1 android.widget.LinearLayout@413304d0
05-09 15:24:00.357: E/MultipleItemList(11109): getView: 2 android.widget.LinearLayout@413304d0
05-09 15:24:00.357: E/MultipleItemList(11109): getView: 3 android.widget.LinearLayout@413304d0
05-09 15:24:00.357: E/MultipleItemList(11109): getView: 4 android.widget.LinearLayout@413304d0
05-09 15:24:00.357: E/MultipleItemList(11109): getView: 5 android.widget.LinearLayout@413304d0
05-09 15:24:00.367: E/MultipleItemList(11109): getView: 6 android.widget.LinearLayout@413304d0
05-09 15:24:00.367: E/MultipleItemList(11109): getView: 7 android.widget.LinearLayout@413304d0
05-09 15:24:00.367: E/MultipleItemList(11109): getView: 8 android.widget.LinearLayout@413304d0
05-09 15:24:00.367: E/MultipleItemList(11109): getView: 9 android.widget.LinearLayout@413304d0
05-09 15:24:00.407: E/MultipleItemList(11109): getView: 0 android.widget.LinearLayout@413304d0
05-09 15:24:00.407: E/MultipleItemList(11109): getView: 1 null
05-09 15:24:00.407: E/MultipleItemList(11109): getView: 2 null
05-09 15:24:00.417: E/MultipleItemList(11109): getView: 3 null
05-09 15:24:00.417: E/MultipleItemList(11109): getView: 4 null
05-09 15:24:00.417: E/MultipleItemList(11109): getView: 5 null
05-09 15:24:00.427: E/MultipleItemList(11109): getView: 6 null
05-09 15:24:00.427: E/MultipleItemList(11109): getView: 7 null
05-09 15:24:00.437: E/MultipleItemList(11109): getView: 8 null
05-09 15:24:00.437: E/MultipleItemList(11109): getView: 9 null
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 0 null
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 1 android.widget.LinearLayout@41338b60
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 2 android.widget.LinearLayout@41338b60
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 3 android.widget.LinearLayout@41338b60
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 4 android.widget.LinearLayout@41338b60
05-09 15:24:00.457: E/MultipleItemList(11109): getView: 5 android.widget.LinearLayout@41338b60
05-09 15:24:00.467: E/MultipleItemList(11109): getView: 6 android.widget.LinearLayout@41338b60
05-09 15:24:00.467: E/MultipleItemList(11109): getView: 7 android.widget.LinearLayout@41338b60
05-09 15:24:00.467: E/MultipleItemList(11109): getView: 8 android.widget.LinearLayout@41338b60
05-09 15:24:00.467: E/MultipleItemList(11109): getView: 9 android.widget.LinearLayout@41338b60

Why on earth is there so much work going into rendering the first 10 items in the list?

Josh
  • 12,448
  • 10
  • 74
  • 118
  • The only real difference I can see between your code and the code in the tutorial is that the tutorial uses a `ListActivity` instead of an `Activity`. It might be possible that there are slight differences between the behaviour of a `ListView` in an `Activity` and a `ListActivity`. If you follow the tutorial exactly do you get the same results? – Louth May 09 '12 at 21:16
  • @Louth: That I'm not sure of. I don't plan on using a ListActivity in my application, so I don't know that it's worth exploring too heavily. I'd think the behaviour shouldn't deviate regardless of where the ListActivity "lives". – Josh May 09 '12 at 21:24
  • 1
    possible duplicate: http://stackoverflow.com/questions/2618272/custom-listview-adapter-getview-method-being-called-multiple-times-and-in-no-co – Timuçin May 09 '12 at 22:21
  • @Tim thanks, I'll check that out when I'm home. Their logic seems very sound, and matches my problem perfectly – Josh May 09 '12 at 23:44

1 Answers1

2

The differences between the calls to getView seen in your Activity and the calls to getView seen in the tutorial occur because the tutorial uses a ListActivity. There is some underlying difference in the way Adapters get called when using the different activity classes.

I took the code in the code in your question and was able to reproduce the logs you reported. When I changed it to extend from a ListActivity I was able to reproduce the logs seen in the tutorial.

Looking into the StackTraceElements for the getView() I can see the following:

Activity Log

getView: pos[0] convertView[null]
CallerClass[android.widget.AbsListView] CallerMethod[obtainView]
CallerClass[android.widget.ListView] CallerMethod[measureHeightOfChildren]
CallerClass[android.widget.ListView] CallerMethod[onMeasure]
CallerClass[android.view.View] CallerMethod[measure]
CallerClass[android.view.ViewGroup] CallerMethod[measureChildWithMargins]
CallerClass[android.widget.LinearLayout] CallerMethod[measureChildBeforeLayout]
CallerClass[android.widget.LinearLayout] CallerMethod[measureVertical]
CallerClass[android.widget.LinearLayout] CallerMethod[onMeasure]
CallerClass[android.view.View] CallerMethod[measure]
CallerClass[android.view.ViewGroup] CallerMethod[measureChildWithMargins]
CallerClass[android.widget.FrameLayout] CallerMethod[onMeasure]
CallerClass[android.view.View] CallerMethod[measure]
CallerClass[android.widget.LinearLayout] CallerMethod[measureVertical]
CallerClass[android.widget.LinearLayout] CallerMethod[onMeasure]
CallerClass[android.view.View] CallerMethod[measure]
CallerClass[android.view.ViewGroup] CallerMethod[measureChildWithMargins]
CallerClass[android.widget.FrameLayout] CallerMethod[onMeasure]
CallerClass[com.android.internal.policy.impl.PhoneWindow$DecorView] CallerMethod[onMeasure]
CallerClass[android.view.View] CallerMethod[measure]
CallerClass[android.view.ViewRootImpl] CallerMethod[performTraversals]
CallerClass[android.view.ViewRootImpl] CallerMethod[handleMessage]
CallerClass[android.os.Handler] CallerMethod[dispatchMessage]
CallerClass[android.os.Looper] CallerMethod[loop]
CallerClass[android.app.ActivityThread] CallerMethod[main]
CallerClass[java.lang.reflect.Method] CallerMethod[invokeNative]
CallerClass[java.lang.reflect.Method] CallerMethod[invoke]
CallerClass[com.android.internal.os.ZygoteInit$MethodAndArgsCaller] CallerMethod[run]
CallerClass[com.android.internal.os.ZygoteInit] CallerMethod[main]
CallerClass[dalvik.system.NativeStart] CallerMethod[main]

ListActivity.log

getView: pos[0] convertView[null]
CallerClass[android.widget.AbsListView] CallerMethod[obtainView]
CallerClass[android.widget.ListView] CallerMethod[makeAndAddView]
CallerClass[android.widget.ListView] CallerMethod[fillDown]
CallerClass[android.widget.ListView] CallerMethod[fillFromTop]
CallerClass[android.widget.ListView] CallerMethod[layoutChildren]
CallerClass[android.widget.AbsListView] CallerMethod[onLayout]
CallerClass[android.view.View] CallerMethod[layout]
CallerClass[android.view.ViewGroup] CallerMethod[layout]
CallerClass[android.widget.FrameLayout] CallerMethod[onLayout]
CallerClass[android.view.View] CallerMethod[layout]
CallerClass[android.view.ViewGroup] CallerMethod[layout]
CallerClass[android.widget.LinearLayout] CallerMethod[setChildFrame]
CallerClass[android.widget.LinearLayout] CallerMethod[layoutVertical]
CallerClass[android.widget.LinearLayout] CallerMethod[onLayout]
CallerClass[android.view.View] CallerMethod[layout]
CallerClass[android.view.ViewGroup] CallerMethod[layout]
CallerClass[android.widget.FrameLayout] CallerMethod[onLayout]
CallerClass[android.view.View] CallerMethod[layout]
CallerClass[android.view.ViewGroup] CallerMethod[layout]
CallerClass[android.view.ViewRootImpl] CallerMethod[performTraversals]
CallerClass[android.view.ViewRootImpl] CallerMethod[handleMessage]
CallerClass[android.os.Handler] CallerMethod[dispatchMessage]
CallerClass[android.os.Looper] CallerMethod[loop]
CallerClass[android.app.ActivityThread] CallerMethod[main]
CallerClass[java.lang.reflect.Method] CallerMethod[invokeNative]
CallerClass[java.lang.reflect.Method] CallerMethod[invoke]
CallerClass[com.android.internal.os.ZygoteInit$MethodAndArgsCaller] CallerMethod[run]
CallerClass[com.android.internal.os.ZygoteInit] CallerMethod[main]
CallerClass[dalvik.system.NativeStart] CallerMethod[main]

So my answer would be that there are key differences in the way ListViews in the different activity types are populated/rendered and this causes the differences in the amount of calls to getView.

Louth
  • 11,401
  • 5
  • 28
  • 37
  • 1
    This and the answer linked to in the comment on my post were the problems. When you don't use fill_parent for both width and height of a ListView (as I'm guessing extending ListActivity does), Android has to layout without rendering, the whole list so it can measure it, then it starts rendering. When it fills or matches parent, the dimensions are known. – Josh May 11 '12 at 13:26