Теперь мы собираемся закодировать плавную прокрутку нашего Android ListView. В предыдущем посте мы попытались понять, как работает ListView с адаптером. На этот раз речь пойдет о производительности.
Я сделал это отдельным постом, потому что Android ListView иногда трудно понять . Я имею в виду: «Сначала мы должны сделать основы, а затем применить оптимизацию».
Что с шаблоном ViewHolder?
Шаблон проектирования ViewHolder позволяет получить доступ к каждому представлению элемента списка без необходимости поиска, сохраняя ценные циклы процессора. В частности, он позволяет избежать частого вызова findViewById () во время прокрутки ListView, и это сделает его гладким.
Без шаблона проектирования ViewHolder
Хорошо, давайте раскопаем это и посмотрим, как это работает без шаблона ViewHolder.
Давайте посмотрим на наш предыдущий метод getView () в ArrayAdapterItem.java
- При первой загрузке convertView имеет значение null. Нам придется накачать наш элемент списка и найти TextView с помощью findViewById ().
- Во второй раз, когда он был загружен, convertView не является нулевым, хорошо! Мы не должны раздувать это снова. Но мы снова будем использовать findViewById ().
- В следующий раз, когда он был загружен, convertView определенно не равен нулю. Но findViewById () постоянно вызывается, он будет работать, но он замедляет производительность, особенно если у вас много элементов и представлений в вашем ListView.
С помощью шаблона проектирования ViewHolder
Теперь давайте посмотрим, как это работает с шаблоном ViewHolder.
- При первой загрузке convertView имеет значение null. Нам придется накачать наш макет элемента списка, создать экземпляр ViewHolder, найти TextView с помощью findViewById (), назначить его ViewHolder и установить ViewHolder в качестве тега convertView.
- Во второй раз, когда он был загружен, convertView не является нулевым, хорошо! Мы не должны раздувать это снова. И вот что приятно, нам не нужно вызывать findViewById (), поскольку теперь мы можем получить доступ к TextView через его ViewHolder.
- В следующий раз, когда он был загружен, 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.