I have the following structure in my app:
FragmentActivity with ViewPager
holding multiple fragments managed by FragmentStatePagerAdapter
using
I had a similar problem and it took me 2 days to debug and solve it. I have a ListAdapter which creates several TextViews in a LinearLayout for every list item. Each TextView has it's own OnClickListener, because I need to handle clicks on each item.
When I changed the implementation so that I reuse the Views the OnClickListener stopped working correctly. On 4.4.2 most clicks worked but sometimes there was no reaction until I scrolled in the list. On 2.3 the first clicks would not work and then all clicks where handled in a burst.
In my special case I created all the View in Java code and not by inflating resources. And the critical point was, that I did set the LayoutParams of the LinearLayout even when the view was reused (this seems to be more safe, then assuming that the reused view has the correct layout parameters). When I don't set the LayoutParams when reusing everything works fine! Here is the critical code:
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout tapeLine = null;
if (convertView != null && convertView instanceof LinearLayout && ((LinearLayout)convertView).getChildCount() == 4) tapeLine = (LinearLayout) convertView; // Reuse view
else tapeLine = new LinearLayout(activity);
if (convertView == null) { // Don't set LayoutParams when reusing view
ViewGroup.LayoutParams tapeLineLayoutParams = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tapeLine.setLayoutParams(tapeLineLayoutParams);
}
ScrollingTape scrollingTape = calculatorHolder.getCalculator().getScrollingTape();
int tapeWidthPx = parent.getWidth();
TapeLineTextSizeInfo tapeLineTextSizeInfo = calculatorHolder.getTapeLineTextSizeHelper().createTapeLineTextSizeInfo(tapeWidthPx);
ScrollingTapeLine line = scrollingTape.getLine(position);
tapeLine.setOrientation(LinearLayout.HORIZONTAL);
int tapeBackgroundColor = getBackgroundColor(line);
tapeLine.setBackgroundColor(tapeBackgroundColor);
addColumnViews(tapeLine, line, tapeLineTextSizeInfo);
tapeLine.setTag(R.id.scrollingtapeadapter_viewtag_position, position);
tapeLine.setOnLongClickListener(longClickListener);
tapeLine.setOnClickListener(remainClickListener);
return tapeLine;
}
What is the background for this strange behaviour of the list view? I did a bit of debugging and research in the Android sources. When android updates a view there are two important steps onMeasure and onLayout. The getView method of the ListAdapter is not only called to draw the view but also earlier during onMeasure. In this later case the view is created but it is not yet registered in the event chain to handle click events.
When a view which has been created for onMeasure is reused later to be acutally drawn to the screen, it must be register from the Android system to handle click events. For this special case the Android develepers had done something, which could be considered as a dirty hack. A special flag in the LayoutParams is used to decide that the view has to be registered in the event change.
Now my problem: by resetting the LayoutParams also when a view is reused, this flag was always reset. Therefore the Android system would not register the view and events would not come through.
to summarize: when resusing a view in getView of a ListAdapter don't overwrite the LayoutParams because they keep internal information of the android system.