I (as many other) have problems getting smooth performance in my listview. I believe I have done everything by the book, but it still lags significantly (~300-500 ms)every time a new item is being drawn on the screen.
I'm using a viewHolder and reusing as many UI elements as possible (I think). There are two clear bottle necks.
The first is the line inflating the XML code in the newView() method. That is for some reason really slow (~300 ms) and I don't know if this is expected or not.
Secondly the bindView takes a long time to execute. This is only because of the TextView.setText() method calls which takes up all the time. Other people have had the same problem and I do understand that it can be a slow thing if Android needs to remeasure the entire UI for every listitem. However, after changing the XML file TextViews to a fixed size I still get really slow performance from .setText(). I know I could put the .setText in a Handler but that seems like a hack in this case. I would prevent the list from being laggy, but it would not add the text any faster. I believe I should be able to set the text faster than ~400 ms and if it takes this long something is wrong with my UI/logic.
But without further ado I present you with the source code: Hope to get some clever insight into what I'm doing wrong.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (ApplicationConfiguration.DEBUGGING)
Debug.startMethodTracing("getview");
View listViewItem;
EpisodeViewHolder holder;
Cursor itemCursor = (Cursor) getItem(position);
if (!itemCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position "
+ position);
}
mCurrentFeedItem = MyListItem.getByCursor(itemCursor);
int type = getItemViewType(position);
if (convertView == null) {
switch (type) {
case TYPE_EXPAND:
listViewItem = newView(mContext, itemCursor, parent);
break;
default:
listViewItem = newView(mContext, itemCursor, parent);
break;
}
} else {
listViewItem = convertView;
}
bindView(listViewItem, mContext, itemCursor);
switch (type) {
case TYPE_EXPAND:
getPlayerViewHolder(position, listViewItem, itemCursor,
convertView, parent);
}
if (ApplicationConfiguration.DEBUGGING)
Debug.stopMethodTracing();
return listViewItem;
}
This is my newView
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = mInflater.inflate(R.layout.episode_list, null); // here is the bottleneck
EpisodeViewHolder holder = new EpisodeViewHolder();
holder.icon = (ImageView) view.findViewById(R.id.list_image);
holder.mainTitle = (TextView) view.findViewById(R.id.title);
holder.subTitle = (TextView) view.findViewById(R.id.podcast);
holder.timeDuration = (TextView) view.findViewById(R.id.duration);
holder.currentPosition = (TextView) view.getTag(R.id.current_position);
holder.slash = (TextView) view.findViewById(R.id.time_slash);
holder.fileSize = (TextView) view.findViewById(R.id.filesize);
holder.stub = (ViewStub) view.findViewById(R.id.stub);
holder.playerView = (View) view.findViewById(R.id.stub_player);
view.setTag(holder);
return view;
}
and my bindView method is really long but I'll shorten it down a bit
@Override
public void bindView(View view, Context context, Cursor cursor) {
.....
final EpisodeViewHolder holder = (EpisodeViewHolder) view.getTag();
.....
// not a bottleneck
// Loads the image Async. The synchronous part of the call takes around 10%
// of the entire method
PicassoWrapper.load(mContext, i, holder.icon);
// This is the bottleneck
holder.mainTitle.setText(title);
}
XML UI
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/thumbnail"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_marginRight="7dip"
android:padding="0dip" >
<ImageView
android:id="@+id/list_image"
style="@style/PodcastImage" />
</LinearLayout>
<TextView
android:id="@+id/title"
style="@style/EpisodeHeaderFont"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_alignTop="@+id/thumbnail"
android:layout_toRightOf="@+id/thumbnail"
android:text="Podcast Title" />
<TextView
android:id="@+id/podcast"
android:layout_width="200dp"
android:layout_height="40dp"
android:layout_above="@+id/current_position"
android:layout_below="@id/title"
android:layout_marginTop="1dip"
android:layout_toRightOf="@+id/thumbnail"
android:ellipsize="end"
android:text="Podcast Name"
android:textSize="10dip" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/current_position"
style="@style/EpisodeMinorFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/thumbnail"
android:layout_toRightOf="@+id/thumbnail" />
<TextView
android:id="@+id/time_slash"
style="@style/EpisodeMinorFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/current_position"
android:layout_alignBottom="@+id/current_position"
android:layout_toRightOf="@+id/current_position"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:visibility="gone" />
<TextView
android:id="@+id/duration"
style="@style/EpisodeMinorFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/time_slash"
android:layout_alignBottom="@+id/time_slash"
android:layout_toRightOf="@+id/time_slash" />
<TextView
android:id="@+id/filesize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/duration"
android:layout_toRightOf="@+id/duration"
android:gravity="bottom|right"
android:text="0"
android:textSize="10dip"
android:textStyle="bold" />
</RelativeLayout>
<FrameLayout
android:id="@id/drag_handle"
android:layout_width="25dp"
android:layout_height="match_parent"
android:paddingBottom="30dp"
android:paddingTop="30dp" >
<LinearLayout
android:layout_width="7dp"
android:layout_height="fill_parent"
android:background="@drawable/drag_handle"
android:orientation="vertical"
android:tileMode="repeat" >
</LinearLayout>
</FrameLayout>
</LinearLayout>
<ViewStub
android:id="@+id/stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/stub_player"
android:layout="@layout/list_item_expanded" />