Як працює механізм переробки ListView


146

Тож у мене ця проблема була в мене раніше, і я, природно, попросив допомоги тут . Відповідь Luksprog була чудовою, тому що я не мав уявлення про те, як ListView та GridView оптимізували себе за допомогою переробки 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, це в основному все, що вам потрібно, щоб зрозуміти, як працює ListView. Посилання на коментарі померло. Тож користувачеві3427079 було досить приємно оновити це посилання. Ось це для легкого доступу.


Ха-ха, дякую за це посилання. Почав дивитися зараз :)
Енді

Ви не повністю реалізували зразок коду з попереднього питання. Ідея полягає в тому, що вам завжди потрібно мати фрагмент коду, щоб повернути зміни, які ви внесли для інших рядків (у вашому випадку позиції 0).
Лукспрог

Добре я розумію, що @Luksprog Але це пояснює, чому його також ставлять Погляд на інші позиції? Якщо що, я очікував, що лише позиція 0 матиме повторювані представлення даних. Idk, все ще виникають проблеми з розумінням того, як ListView прив’язує цей матеріал: /
Енді

1
Переробка означає, що щойно зниклий вид рядка (наприклад, позиція 0, після прокручування одного рядка вниз) з екрана може бути використаний пізніше, коли ListViewпотрібен новий рядок для показу (наприклад, продовження прокрутки вниз / вгору). Проблема полягає в тому, що погляд, який щойно зник і який буде використовуватися на майбутніх необхідних посадах, TextViewвже додав до цього, в цьому і полягає проблема. Щоб вирішити його, вам потрібно видалити його в getViewметоді, якщо getViewметод викликається в будь-якій іншій позиції, ніж 0.
Luksprog

2
Посилання на верхній пост мертве, я думаю, що це? youtube.com/watch?v=N6YdwzAvwOA
G_V

Відповіді:


330

Спочатку я також не знав про переробку списку перегляду та механізм використання converviewview, але після цілоденних досліджень я дуже розумію механізми перегляду списку, посилаючись на зображення з android.amberfog введіть тут опис зображення

Щоразу, коли ваш перегляд списку заповнюється адаптером, він в основному показує кількість рядків, які перегляд списку може відображатися на екрані, а кількість рядків не збільшується, навіть якщо ви прокручуєте список. Це хитрість андроїда використовує, щоб listview працював ефективніше і швидше. Тепер внутрішній сюжет перегляду списку, що посилається на зображення, як ви бачите, спочатку перегляд списку містить 7 видимих ​​елементів, потім, якщо прокрутити вгору, поки елемент 1 вже не буде видно, getView () передає цей погляд (тобто item1) в переробник і ви можете використовувати

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;
    }

Ви помітите у своїй логічній котці, спочатку файл перегляду є нульовим для всіх видимих ​​рядків, оскільки спочатку в переробнику не було переглядів (тобто елементів), тому ваш getView () створює новий вид для кожного з видимих ​​елементів, але Якщо ви прокрутите вгору і пункт 1 переміститься з екрана, він буде надісланий Утилізатору в його теперішньому стані (наприклад, "Текст" TextView або в моєму випадку, якщо прапорець встановлений, він буде пов'язаний з представленням і зберігається в утилізаторі).

Тепер, коли ви прокручуєте вгору / вниз, ваш перегляд списку не збирається створювати новий вид, він використовуватиме вид, який знаходиться у вашій переробці. У вашому Logcat ви помітите, що "convertView" не є нульовим, це тому, що ваш новий елемент 8 буде намальований за допомогою converviewview, тобто в основному він займає перегляд пункту 1 від переробника і надуває елемент 8 на його місці, і ви можете спостерігати що в моєму коді. Якщо у вас був прапорець і якщо ви поставите його в позиції 0 (скажімо, у елемента1 був прапорець і ви поставили його), тож, коли ви прокрутите вниз, ви побачите, що пункт 8 пункту 8 вже встановлений, тому список перегляду повторно використовує той самий вигляд, не створювати нове для вас завдяки оптимізації продуктивності.

Важливі речі

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

2 . Якщо ви хочете використовувати будь - то макет або подання після подання списку і питання може прийшов в розумі , якщо я встановити layout_heightна fill_parentуявленні після подання списку не буде доступний широкому , як вона йде вниз по екрану, тому його краще поставити ListView всередині Наприклад, лінійний макет і встановіть висоту та ширину цього макета відповідно до вашої вимоги та зробіть атрибут висоти та ширини перегляду списку відповідно до вашого макета (наприклад, якщо ширина макета становить 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 рамок , як він працює, як це дійсно брудно і хитрі тому початківці знайшли дуже багато проблем з розумінням його


36
"Я знаю, що я не так добре в поясненні" >>> +37 голосів на цю відповідь говорить мені, що ви відмінно працювали в поясненні. Будь ласка, продовжуйте ділитися своїми знаннями! ;)
2Dee

1
Відмінна відповідь raja ji +1 від мене .. :)
Ehsan Sajjad

2
Дякую за Образ Коли у мене було багато проблем з ListView, коли я почав працювати з Android, я вже знав принцип утилізації після того, як з цим боровся. І все-таки це сприйняло цю картину і речення: if you had a checkbox and if you check it at position 0(let say item1 has also a checkbox and you checked it) so when you scroll down you will see item 8 checkbox is already checked,this is why listview is re using the same view not creating a new for you due to performance optimization.я зрозумів свою помилку. Найкраща публікація про переробку Android ListView, яку я натрапив!
Кевін Круїссен

1
@MuhammadBabar Так, я відправив питання: stackoverflow.com/q/30122027/1318946
Pratik Butani

1
@MuhammadBabar дивовижне пояснення людини! Це економить мій час. Просто хочу знати, чи працює RecyclerViewтакож той же механізм? У моєму питанні stackoverflow.com/questions/47897770/… , я знаю, що це завдання неможливо listView. Чи варто спробувати recyclerView?
Шамху

8

Обережно, у шаблоні 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..

1
Не помічав, що весь цей час я займався. parent.setTag(holder);замість правильного способу, який є,view.setTag(holder);
ArtiomLK

2

Використовуючи шаблон Holder, ви можете досягти бажаного:

Опис цієї схеми ви можете знайти тут:

Переробка перегляду списків відбувається, коли ви прокручуєте екран вниз, а елементи перегляду списку вище приховані. Вони повторно використовуються для показу нових елементів перегляду списку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.