Механизм как элемент управления ListView по утилизации работает


Итак, у меня есть эта проблема, которую я имел раньше, и, естественно, я попросил о помощи здесь. Ответ Luksprog был отличным, потому что я понятия не имел о том, как ListView и GridView оптимизировали себя с помощью представлений рециркуляции. Поэтому с его советом я смог изменить то, как я добавил взгляды в свой 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 говорите, что в основном все, что вам нужно, чтобы понять, как работает ListView. Ссылка была мертва в одном из комментариев. Поэтому user3427079 был достаточно хорош, чтобы обновить эту ссылку. здесь это для легкого доступа.

3 133

3 ответа:

Первоначально я также не знал о переработке listview и механизме использования convertview, но после целого дня исследований я в значительной степени понимаю механизмы представления списка, ссылаясь на изображение из android.amberfog enter image description here

когда когда-либо ваш listview заполняется адаптером, он в основном показывает количество строки что listview может отображаться на экране, и количество строк не увеличивается даже при прокрутке список, это трюк android использовать так, что listview работать более эффективно и быстро, Теперь внутренняя история listview, ссылающаяся на изображение, как вы можете видеть, изначально список имеет 7 видимых элементов, если вы прокручиваете вверх, когда элемент 1 больше не виден getView () передайте этот вид (item1) в recycler, и вы можете использовать

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 для всех видимых строк, потому что изначально не было view (item) в recycler, поэтому ваш getView () создает каждый новый вид для видимых элементов, но в тот момент, когда вы прокручиваете свой элемент 1, он будет отправлен в ресайклер С его состоянием (например, текст TextView и, как в моем случае, если флажок установлен, он также будет связан с представлением и хранением в recycler). Теперь, когда вы прокручиваете вверх / вниз ваш listview не собирается создавать новый вид, он будет использовать вид (конвертировать вид), который уже находится в вашем recycler, в вашем Logcat вы заметите, что convertView уже не null, это потому что ваш новый пункт 8 может быть нарисован с использованием convertview, т. е. в основном это взять элемент1 вид из переработчик и насос на место пункта 8, и вы можете наблюдать за тем, как в мой код если у вас был флажок, и если вы установите его в положение 0(скажем элемент1 также галку и вы проверили), поэтому, когда вы прокрутите вниз, вы увидите пункт 8 флажок уже установлен, вот почему ListView является повторное использование той же точки зрения не создание нового для вас за счет оптимизации производительности.

важные вещи

1. Никогда не устанавливайте layout_height и layout_width из вашего listview в wrap_content как getView() заставит ваш адаптер получить некоторого ребенка для измерения высоты представлений, которые будут нарисованы в виде списка, и может вызвать некоторое неожиданное поведение, например, возврат convertview, даже если список не прокручивается.всегда используйте match_parent или фиксированный ширина/высота.

2. Если вы хотите использовать какой-то макет или представление после просмотра списка и вопрос может прийти в голову, если я установил layout_height до fill_parent вид после просмотра списка не будет отображаться, когда он идет вниз по экрану, поэтому лучше поместить свой listview внутри макета.Например, линейный макет и установите высоту и ширину этого макета по вашему требованию и сделайте высота и ширина атрибут вашего listview в as вашего макета(например, если ваша ширина макета 320 и высотой 280) тогда ваш listview должен иметь то же самое высота и ширина. Это скажет getView () о точной высоте и ширине представлений, которые будут отображаться, и getView() не будет вызывать снова и снова некоторые случайные строки, а также другие проблемы, такие как возврат convert view даже до прокрутки не произойдет, я сам это проверяю, если только мой listview не был внутри lineaLayout это также было возникают проблемы, такие как повторяющий вид звонка и преобразовать вид как, поставив внутри элемента управления ListView макет работал, как по волшебству для меня.(не знаю почему)

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 рамки, как это работает, как это действительно грязно и сложно так новички нашли слишком много проблем, понимая это

будьте осторожны, в шаблоне держателя, если вы устанавливаете положение в своем объекте держателя, вы должны устанавливать его каждый раз , например :

@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..

используя шаблон держателя вы можете достичь того, что вы хотите:

вы можете найти описание этого узора здесь:

рециркуляция списка происходит, когда вы прокручиваете вниз экран и выше элементы списка скрыты . Они используются повторно для отображения новых элементов списка.