Crake Crake - 1 month ago 15
Android Question

Yet Another ListView custom adapter getView called way too many times

I have a custom adapter and getView is being called a ton of times on position 0. I have read a bunch of similar questions and most of them point to setting height of ListView to be "wrap_content" as the culprit. My ListView and rows are all set to fill_parent or match_parent, none of them are set to wrap_content.

While I am aware that getView can be called in any order and any number of times, it seems that I must be doing something wrong to produce this many calls for position 0 (see log below). What are some other potential causes for getView being called so many times?

07-22 11:48:03.032: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 5
07-22 11:48:03.082: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.092: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.102: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.112: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.152: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.162: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.192: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.202: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.332: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 6
07-22 11:48:03.392: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.402: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.412: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.422: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.472: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.482: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.492: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.492: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.542: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.552: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.562: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:03.562: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.602: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 7
07-22 11:48:05.642: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.652: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.662: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.672: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.692: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.712: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.712: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.722: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.862: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 8
07-22 11:48:05.922: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.952: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.962: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:05.972: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.012: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.012: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.022: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.032: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.062: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.102: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.102: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.112: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.412: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 9
07-22 11:48:06.442: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.452: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.452: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.462: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.492: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.492: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.502: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.502: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.702: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 10
07-22 11:48:06.762: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.772: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.782: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.792: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.822: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.832: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.862: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.872: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.892: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.902: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0
07-22 11:48:06.912: INFO/com.thisclicks.appdataroom(28989): Masonry adapter fetching view for position 0


Here is my ListView:

<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/categorylist_divider"
android:headerDividersEnabled="false"
android:drawSelectorOnTop="false" android:choiceMode="singleChoice"
android:clickable="false" android:divider="@color/categorylist_divider" android:dividerHeight="10.0sp"
android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_below="@+id/header" />


And the row:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#eeeeee">
<ImageView
android:layout_width="fill_parent"
android:layout_height="20dp"
android:id="@+id/ivHeader" android:background="@color/categorylist_divider"
android:layout_alignParentTop="true"/>

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:useDefaultMargins="true" android:clipChildren="false"
android:layout_height="match_parent" android:id="@+id/masonryrow_layout" android:columnCount="3"
android:rowCount="2" android:background="#eeeeee" android:layout_below="@+id/ivHeader">
</GridLayout>
</RelativeLayout>


Here is the code for getView:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

Log.i(TAG, String.format("Masonry adapter fetching view for position %d", position));
View vi=convertView;
int rowType = determineRowType(position);
ViewHolder holder;
if(convertView==null)
{
Log.i(TAG, String.format("Masonry adapter building view for position %d", position));
vi = buildView(parent, rowType);
}

holder = (ViewHolder) vi.getTag();
int columnWidth = (parent.getWidth()-20)/holder.layout.getColumnCount();
if(holder.columnWidth != columnWidth)
{
Log.i(TAG, "Column width mismatch, rebuilding view");
vi = buildView(parent, rowType);
holder = (ViewHolder) vi.getTag();
}


//hide header and footer spacing
if(position != 0)
{
if(holder.ivHeader != null)
holder.ivHeader.setVisibility(View.GONE);
}
else
{
if(holder.ivHeader != null)
holder.ivHeader.setVisibility(View.VISIBLE);
}



int rowCapacity = calculateRowCapacity(rowType);


for(int i = 1; i <= rowCapacity; i++)
{
CellHolder cellHolder = holder.cells.get(i-1);
int realPosition = calculatePosition(position, i);
if(realPosition < data.size())
{
cellHolder.ivMediaTileThumbnail.setVisibility(View.VISIBLE);
cellHolder.tvMediaName.setVisibility(View.VISIBLE);
cellHolder.ivMediaTileCorner.setVisibility(View.VISIBLE);
Media media = data.get(realPosition);

hydrateMediaTileView(realPosition, media, cellHolder);

}
else
{

cellHolder.ivMediaTileThumbnail.setVisibility(View.GONE);
cellHolder.tvMediaName.setVisibility(View.GONE);
cellHolder.ivMediaTileCorner.setVisibility(View.GONE);
}
}

return vi;
}


EDIT: Here is the complete layout that contains the listview (it is a ListFragment):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:clipChildren="true"
android:layout_height="match_parent" android:background="@color/categorylist_divider">
<RelativeLayout
android:layout_width="fill_parent" android:clipChildren="true"
android:layout_height="wrap_content" android:id="@+id/header" android:background="#ca4f37"
android:paddingRight="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ivBack" android:src="@drawable/category_title_bar_backarrow"
android:paddingTop="10dp" android:paddingBottom="10dp" android:paddingLeft="15dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/tvHeaderText" android:textColor="@color/categorylist_headertext"
android:layout_toRightOf="@+id/ivBack" android:layout_centerVertical="true"
android:paddingLeft="15dp" android:textSize="@dimen/categoryList_headertext" android:paddingTop="10dp"
android:paddingBottom="10dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ivHeaderPlus" android:layout_alignParentRight="true"
android:layout_alignTop="@+id/ivBack" android:src="@drawable/title_bar_plus"
android:layout_centerVertical="true" android:paddingTop="10dp"
android:paddingBottom="10dp" android:layout_marginLeft="25dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="Clear"
android:id="@+id/btnLeft" android:layout_centerVertical="true" android:layout_alignParentRight="false"
android:background="@drawable/header_button_background" android:layout_toLeftOf="@+id/btnRight"
android:textSize="@dimen/headerButton_textSize"
android:textColor="@color/categorylist_headertext"/>
<Button
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="Send"
android:id="@+id/btnRight" android:layout_centerVertical="true" android:layout_alignParentRight="true"
android:background="@drawable/header_button_background"
android:textSize="@dimen/headerButton_textSize"
android:textColor="@color/categorylist_headertext" android:layout_marginLeft="25dp"
android:layout_marginRight="25dp" android:paddingLeft="10dp"
android:paddingRight="10dp"/>
</RelativeLayout>
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/categorylist_divider"
android:headerDividersEnabled="false"
android:drawSelectorOnTop="false" android:choiceMode="singleChoice"
android:clickable="false" android:divider="@color/categorylist_divider" android:dividerHeight="10.0sp"
android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_below="@+id/header" />
<WebView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/webView" android:layout_below="@+id/header" android:layout_marginTop="40dp"
android:layout_marginLeft="40dp" android:layout_marginRight="40dp" android:padding="20dp"
android:background="@android:color/background_dark"/>
</RelativeLayout>

Answer

Turns out the culprit was in the ListFragment onCreate. Dynamically setting the ListFragment's root LinearLayout to width of 0 was causing the issue. Commenting this out fixed the adapter problem.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    inflater.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    ViewGroup mRootView = (ViewGroup) inflater.inflate(R.layout.masonry_list, container, false);



    if(model != null && model.getFragmentWeight() != 0)
    {
        mRootView.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, model.getFragmentWeight()));
    }

    return mRootView;
}
Comments