Как работает механизм утилизации ListView
Так что у меня есть проблема, с которой я сталкивался раньше, и, естественно, я попросил помощи здесь. Ответ Luksprog был великолепен, потому что я понятия не имел о том, как ListView и GridView оптимизировали себя с помощью повторного использования Views. Так что с его советом я смог изменить способ добавления Views в мой GridView. Проблема сейчас в том, что у меня что-то не имеет смысла. Это мое getView
от моего BaseAdapter
:
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.day_view_item, parent, false);
}
Log.d("DayViewActivity", "Position is: "+position);
((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
//layout.addView(new EventFrame(parent.getContext()));
TextView create = new TextView(DayViewActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
create.setLayoutParams(params);
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
//the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
//new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)
if(position == 0) {
Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
layout.addView(create);
}
return convertView;
}
}
Проблема в том, что когда я прокручиваю, это происходит, а не в позиции 0... Похоже на позицию 6 и позицию 8, плюс это ставит два в позицию 8. Теперь я все еще пытаюсь освоить использование ListView и GridView, поэтому я делаю не понимаю, почему это происходит. Одна из главных причин, по которой я задаю этот вопрос, - помочь тем, кто, возможно, не знает о перерабатывающем представлении ListView и GridView, или о том, как изложено в этой статье, о механизме ScrapView.
Позже Править
Добавление ссылки на Google IO talk - это практически все, что вам нужно, чтобы понять, как работает ListView. Ссылка была мертвой в одном из комментариев. Так что user3427079 был достаточно хорош, чтобы обновить эту ссылку. Здесь это для легкого доступа.
3 ответа
Сначала я также не знал об утилизации списков и механизме использования convertview, но после целого дня исследований я в значительной степени понимаю механизмы представления списков, ссылаясь на изображение из http://android.amberfog.com/?p=296.
Когда ваше представление списка заполнено адаптером, оно в основном показывает количество строк, которое список может отображать на экране, и количество строк не увеличивается даже при прокрутке списка, это прием для Android, так что просмотр списка работает более эффективно и быстро, теперь внутренняя история представления списка, обращенного к изображению, как вы можете видеть, изначально отображает список, имеет 7 видимых элементов, если вы прокрутите вверх, когда элемент 1 больше не виден, getView() передаст этот вид (item 1) переработчику, и вы сможете использование
System.out.println("getview:"+position+" "+convertView);
внутри вашего
public View getView(final int position, View convertView, ViewGroup parent)
{
System.out.println("getview:"+position+" "+convertView);
ViewHolder holder;
View row=convertView;
if(row==null)
{
LayoutInflater inflater=((Activity)context).getLayoutInflater();
row=inflater.inflate(layoutResourceId, parent,false);
holder=new PakistaniDrama();
holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
row.setTag(holder);
}
else
{
holder=(PakistaniDrama)row.getTag();
}
holder.tvDramaName.setText(dramaList.get(position).getDramaName());
holder.cbCheck.setChecked(checks.get(position));
return row;
}
вы заметите, что в вашем logcat изначально convertview имеет значение null для всех видимых строк, потому что изначально в утилите не было представления (элемента), поэтому ваш getView() создает каждое новое представление для видимых элементов, но в момент прокрутки вашего элемента 1 отправит Recycler с его состоянием (например, текст TextView и, как в моем случае, если флажок установлен, он также будет связан с представлением и сохранен в утилите). Теперь, когда вы прокручиваете вверх / вниз, ваше представление списка не собирается создавать новое представление, оно будет использовать представление (представление конвертирования), которое уже находится в вашем утилизаторе, в вашем Logcat вы заметите, что convertView не является нулевым, потому что ваш новый элемент 8 будет нарисован с использованием convertview, то есть, в основном, он берет представление item 1 из рециркулятора и инфлатера вместо элемента 8, и вы можете наблюдать это как в моем коде, если у вас есть флажок и если вы проверяете его в позиции 0(пусть скажем, у item 1 также есть флажок, и вы отметили его), поэтому при прокрутке вниз вы увидите, что флажок item 8 уже установлен, поэтому listview использует то же представление, но не создает для вас новое из-за оптимизации производительности.
Важные вещи
1 Никогда не устанавливайте layout_height
а также layout_width
вашего списка в wrap_content
как getView()
вынудит ваш адаптер получить дочерний элемент для измерения высоты представлений, которые будут отображаться в виде списка, и может вызвать непредвиденное поведение, например, возвращать convertview, даже если список не прокручивается. всегда используйте match_parent
или фиксированная ширина / высота.
2 Если вы хотите использовать какой-либо макет или вид после представления списка, и у вас может возникнуть вопрос, если я установлю layout_height
в fill_parent
представление после списка не будет отображаться при перемещении вниз по экрану, поэтому лучше поместить свой список внутри макета. Например, Linear Layout и установить высоту и ширину этого макета в соответствии с вашими требованиями, а также сделать высоту и ширину Присвойте вашему списку вид вашего макета (например, если ширина макета равна 320, а высота равна 280), тогда ваш список должен иметь одинаковую высоту и ширину. Это скажет getView() о точной высоте и ширине представлений, которые будут отображаться, и getView() не будет снова и снова вызывать некоторые случайные строки, и другие проблемы, такие как возвращение представления преобразования даже до того, как прокрутка не произойдет, у меня есть тест это само по себе, если мой просмотр списка не был внутри lineaLayout, у него также были проблемы, такие как повторение вызова представления и преобразование представления, так как размещение Listview внутри LinearLayout работало для меня как волшебство (не знаю почему)
01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null
Но теперь это решено, я знаю, я не так хорош в объяснении, но, как я потратил весь свой день, чтобы понять, я думал, что другие новички, как я, могут получить помощь из моего опыта, и я надеюсь, что теперь вы, люди, будете иметь немного понимания фреймворка ListView, как он работает, так как он действительно запутанный и хитрый, поэтому новичкам было слишком сложно понять его
Будьте внимательны, в паттерне Holder, если вы устанавливаете положение в вашем объекте Holder, вы должны устанавливать его каждый раз, например:
@Override
public final View getView(int position, View view, ViewGroup parent) {
Holder holder = null;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) App.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(getContainerView(), parent, false);
holder = getHolder(position, view, parent);
holder.setTag(tag);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
holder.position = position;
draw(holder);
return holder.getView();
}
это пример из абстрактного класса, где
getHolder(position, view, parent);
выполняет все операции настройки для
ImageViews, TextViews, etc..
Используя шаблон Holder, вы можете достичь того, что вы хотите:
Вы можете найти описание этого шаблона здесь:
Повторное использование представления списка происходит, когда вы прокручиваете экран вниз, и вышеупомянутые элементы представления списка скрыты. Они повторно используются для отображения новых элементов представления списка.