Статьи

Пример Android ViewHolder Pattern

Теперь мы собираемся закодировать плавную прокрутку нашего Android ListView. В предыдущем посте мы попытались понять, как работает ListView с адаптером. На этот раз речь пойдет о производительности.

Я сделал это отдельным постом, потому что Android ListView иногда трудно понять . Я имею в виду: «Сначала мы должны сделать основы, а затем применить оптимизацию».

Что с шаблоном ViewHolder?

Шаблон проектирования ViewHolder позволяет получить доступ к каждому представлению элемента списка без необходимости поиска, сохраняя ценные циклы процессора. В частности, он позволяет избежать частого вызова findViewById () во время прокрутки ListView, и это сделает его гладким.

Без шаблона проектирования ViewHolder

Хорошо, давайте раскопаем это и посмотрим, как это работает без шаблона ViewHolder.

Давайте посмотрим на наш предыдущий метод getView () в ArrayAdapterItem.java

  1. При первой загрузке convertView имеет значение null. Нам придется накачать наш элемент списка и найти TextView с помощью findViewById ().
  2. Во второй раз, когда он был загружен, convertView не является нулевым, хорошо! Мы не должны раздувать это снова. Но мы снова будем использовать findViewById ().
  3. В следующий раз, когда он был загружен, convertView определенно не равен нулю. Но findViewById () постоянно вызывается, он будет работать, но он замедляет производительность, особенно если у вас много элементов и представлений в вашем ListView.

С помощью шаблона проектирования ViewHolder

Теперь давайте посмотрим, как это работает с шаблоном ViewHolder.

  1. При первой загрузке convertView имеет значение null. Нам придется накачать наш макет элемента списка, создать экземпляр ViewHolder, найти TextView с помощью findViewById (), назначить его ViewHolder и установить ViewHolder в качестве тега convertView.
  2. Во второй раз, когда он был загружен, convertView не является нулевым, хорошо! Мы не должны раздувать это снова. И вот что приятно, нам не нужно вызывать findViewById (), поскольку теперь мы можем получить доступ к TextView через его ViewHolder.
  3. В следующий раз, когда он был загружен, convertView определенно не равен нулю. FindViewById () никогда не вызывается снова, и это делает нашу плавную прокрутку ListView.

Давайте код!

Так что вот, мы будем использовать шаблон Android ViewHolder в нашем ListView (всего за 3 шага!).

Шаг 1 : Добавьте следующий статический класс в наш файл ArrayAdapterItem.java

1
2
3
4
5
// our ViewHolder.
// caches our TextView
static class ViewHolderItem {
    TextView textViewItem;
}

Шаг 2 : Наш getView () теперь будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
public View getView(int position, View convertView, ViewGroup parent) {
 
    ViewHolderItem viewHolder;
 
    /*
     * The convertView argument is essentially a "ScrapView" as described is Lucas post
     * It will have a non-null value when ListView is asking you recycle the row layout.
     * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
     */
    if(convertView==null){
 
        // inflate the layout
        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);
 
        // well set up the ViewHolder
        viewHolder = new ViewHolderItem();
        viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
 
        // store the holder with the view.
        convertView.setTag(viewHolder);
 
    }else{
        // we've just avoided calling findViewById() on resource everytime
        // just use the viewHolder
        viewHolder = (ViewHolderItem) convertView.getTag();
    }
 
    // object item based on the position
    ObjectItem objectItem = data[position];
 
    // assign values if the object is not null
    if(objectItem != null) {
        // get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
        viewHolder.textViewItem.setText(objectItem.itemName);
        viewHolder.textViewItem.setTag(objectItem.itemId);
    }
 
    return convertView;
 
}

Шаг 3. Ради тестирования мы собираемся поместить тысячи элементов в наш ListView. На нашем MainActivity.java наш showPopUp () теперь будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public void showPopUp(){
 
    // we'll specify the number of items we want our ListView to have.
    int numberOfItems = 1000;
 
    // add your items, this can be done programatically
    // your items can be from a database
    ObjectItem[] ObjectItemData = new ObjectItem[numberOfItems];
 
    // we'll use a for loop
    // created objects = number of items specified above
    for(int x=0; x<numberOfItems; x++){
 
        int sampleId = 90 + x;
        ObjectItemData[x] = new ObjectItem(sampleId, "Store # " + (x+1));
 
    }
 
    // our adapter instance
    ArrayAdapterItem adapter = new ArrayAdapterItem(this, R.layout.list_view_row_item, ObjectItemData);
 
    // create a new ListView, set the adapter and item click listener
    ListView listViewItems = new ListView(this);
    listViewItems.setAdapter(adapter);
    listViewItems.setOnItemClickListener(new OnItemClickListenerListViewItem());
 
    // put the ListView in the pop up
    alertDialogStores = new AlertDialog.Builder(MainActivity.this)
        .setView(listViewItems)
        .setTitle("Stores")
        .show();
 
}

Я протестировал этот код с 2000 пунктами, и производительность по-прежнему стабильна и великолепна.

Что дальше?

Если у вас есть другие идеи по этой теме, пожалуйста, оставьте их в разделе комментариев ниже. Я более чем готов обновить этот пост и улучшить жизнь человечества.

В следующем посте мы попытаемся использовать AsyncTask для загрузки изображения в ListView. Что-то вроде того, как это делает приложение Google Play Store.

Ссылка: пример шаблона Android ViewHolder от нашего партнера по JCG Майка Далисая из блога «Код ниндзя» .