У меня была похожая проблема, и мне потребовалось 2 дня, чтобы отладить и решить ее.
У меня есть ListAdapter, который создает несколько TextViews в LinearLayout для каждого элемента списка.
Каждый TextView имеет свой собственный OnClickListener, потому что мне нужно обрабатывать клики по каждому элементу.
Когда я изменил реализацию для повторного использования Views, OnClickListener перестал работать правильно. На 4.4.2 большинство нажатий работало, но иногда не было реакции, пока я не прокрутил список. На 2.3 первые клики не будут работать, а затем все клики, где обрабатывается в серии.
В моем особом случае я создал весь код View в Java, а не раздувая ресурсы.
И критическим моментом было то, что я установил LayoutParams LinearLayout, даже когда представление использовалось повторно (это кажется более безопасным, чем при условии, что повторно используемое представление имеет правильные параметры макета).
Когда я не устанавливаю LayoutParams, при повторном использовании все работает отлично!
Вот критический код:
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;
}
Каков фон для этого странного поведения представления списка?
Я немного отладил и исследовал источники Android.
Когда Android обновляет представление, есть два важных шага на Measure и onLayout.
Метод getView ListAdapter вызывается не только для отрисовки представления, но и ранее во время onMeasure. В этом более позднем случае представление создается, но еще не зарегистрировано в цепочке событий для обработки событий щелчка.
Когда представление, созданное для onMeasure, позже используется повторно для точного отображения на экране, оно должно быть зарегистрировано в системе Android для обработки событий щелчка.
Для этого особого случая разработчики Android сделали что-то, что можно было бы считать грязным взломом. Специальный флаг в LayoutParams используется для определения того, что представление должно быть зарегистрировано при изменении события.
Теперь моя проблема: сбрасывая LayoutParams также при повторном использовании представления, этот флаг всегда сбрасывался. Поэтому система Android не будет регистрировать представление, и события не будут проходить.
Подводя итог: при повторном использовании представления в getView ListAdapter не перезаписывайте LayoutParams, поскольку они хранят внутреннюю информацию системы Android.