- Android для начинающих: Общие сведения об адаптерах и видах-адаптерах
- 1. Что такое адаптер?
- 2. Как работают представления адаптера?
- 3. Создание ArrayAdapter
- Шаг 1. Создание набора данных
- Шаг 2. Создание файла ресурсов
- Шаг 3: Создайте адаптер
- 4. Создание списка
- 5. Создание сетки
- 6. Добавление слушателей событий
- 7. Расширение ArrayAdapter
- 8. Использование держателя вида
- Заключение
- Using an ArrayAdapter with ListView
Android для начинающих: Общие сведения об адаптерах и видах-адаптерах
Виды адаптеров настолько повсеместны, что вам нелегко найти популярное приложение для Android, которое их не использует. Название может показаться незнакомым, но если вы думаете, что никогда не видели адаптер, вы, вероятно, ошибаетесь. Каждый раз, когда вы видите элементы интерфейса Android, отображающие элементы пользовательского интерфейса в виде списка, сетки или стека, вы видите представление адаптера в действии.
Представление адаптера, как следует из его названия, является объектом View . Это означает, что вы можете добавить его в свои действия так же, как вы добавляете любой другой виджет пользовательского интерфейса. Однако он не может отображать данные самостоятельно. Его содержимое всегда определяется другим объектом, адаптером. В этом уроке я покажу вам, как создавать адаптеры и использовать их для подачи различных видов адаптеров, таких как ListView и GridView .
Вам легче учиться с видео? Почему бы не проверить наш курс:
1. Что такое адаптер?
Адаптер — это объект класса, который реализует интерфейс Adapter . Он действует как связь между набором данных и видом адаптера, объектом класса, который расширяет абстрактный класс AdapterView . Набор данных может быть любым, что представляет данные структурированным образом. Массивы, объекты List и объекты Cursor являются обычно используемыми наборами данных.
Адаптер отвечает за извлечение данных из набора данных и за создание объектов View на основе этих данных. Сгенерированные объекты View затем используются для заполнения любого вида адаптера, привязанного к адаптеру.
Вы можете создавать собственные классы адаптеров с нуля, но большинство разработчиков предпочитают использовать или расширять классы адаптеров, предоставляемые Android SDK, такие как ArrayAdapter и SimpleCursorAdapter . В этом уроке мы сосредоточимся на классе ArrayAdapter .
2. Как работают представления адаптера?
Представления адаптеров могут очень эффективно отображать большие наборы данных. Например, виджеты ListView и GridView могут отображать миллионы элементов без какого-либо заметного запаздывания, при этом память и загрузка процессора очень низки. Как они это делают? Различные виды адаптеров следуют различным стратегиям. Однако, вот что большинство из них обычно делает.
- Они отображают только те объекты View , которые либо уже присутствуют на экране, либо собираются перемещаться по экрану. Таким образом, память, потребляемая представлением адаптера, может быть постоянной и независимой от размера набора данных.
- Они также позволяют разработчикам свести к минимуму дорогостоящие операции раздувания макетов и перерабатывать существующие объекты View , которые перемещаются за пределы экрана. Это снижает потребление процессора.
3. Создание ArrayAdapter
Чтобы создать адаптер, вам необходимо следующее:
- набор данных
- файл ресурсов, содержащий макет сгенерированных объектов View
Кроме того, поскольку класс ArrayAdapter может работать только со строками, вам нужно убедиться, что макет сгенерированных объектов View содержит хотя бы один виджет TextView .
Шаг 1. Создание набора данных
Класс ArrayAdapter может использовать как массивы, так и объекты List в качестве наборов данных. Пока давайте будем использовать массив в качестве набора данных.
Шаг 2. Создание файла ресурсов
Создайте новый XML-файл макета, корневым элементом которого является LinearLayout и назовите его item.xml. Перетащите в него Large text виджет и установите значение его атрибута id в cheese_name. XML-файл макета должен выглядеть так:
Шаг 3: Создайте адаптер
В своей деятельности создайте новый экземпляр класса ArrayAdapter , используя его конструктор. В качестве аргументов передайте имя файла ресурсов, идентификатор TextView и ссылку на массив. Теперь адаптер готов.
4. Создание списка
Чтобы отобразить вертикально прокручиваемый список элементов, вы можете использовать виджет ListView . Чтобы добавить виджет в свою деятельность, вы можете перетащить его в файл XML макета или создать его с помощью своего конструктора в вашем Java-коде. А пока давайте сделаем последнее.
Как правило, никакие другие виджеты пользовательского интерфейса не помещаются внутри макета, содержащего ListView . Поэтому передайте ListView методу setContentView() вашей деятельности, чтобы он занимал весь экран.
Чтобы связать ListView с адаптером, созданным нами на предыдущем шаге, вызовите метод setAdapter() , как показано ниже.
Если вы сейчас запустите свое приложение, вы сможете увидеть содержимое массива в виде списка.
5. Создание сетки
Чтобы отобразить вертикально прокручиваемую двумерную сетку элементов, вы можете использовать виджет GridView . И ListView , и GridView являются подклассами абстрактного класса AbsListView , и они имеют много общего. Поэтому, если вы знаете, как использовать его, вы также знаете, как использовать другие.
Используйте конструктор класса GridView для создания нового экземпляра и передайте его методу setContentView() вашей активности.
Чтобы установить количество столбцов в сетке, вызовите его метод setNumColumns() . Я собираюсь сделать это двухколоночной сеткой.
Обычно вы хотите настроить ширину столбцов и расстояние между ними, используя методы setColumnWidth() , setVerticalSpacing() и setHorizontalSpacing() . Обратите внимание, что эти методы используют пиксели в качестве единиц.
Теперь вы можете привязать GridView к адаптеру, который мы создали ранее, с помощью метода setAdapter() .
Запустите приложение еще раз, чтобы посмотреть, как выглядит GridView .
6. Добавление слушателей событий
Возможно прослушивание событий щелчка и длинных кликов на элементах внутри вида адаптера. В качестве примера добавим прослушиватель событий щелчка в GridView .
Создайте новый экземпляр анонимного класса, который реализует интерфейс AdapterView.OnItemClickListener и передает его методу setOnItemClickListener() объекта GridView . Android Studio автоматически создает заглушку для метода onItemClick() интерфейса. Вы заметите, что параметры метода включают целое число, определяющее позицию элемента списка. Вы можете использовать это целое число, чтобы узнать, какой элемент в наборе данных пользователь нажал.
Следующий код иллюстрирует, как отображать простое сообщение в качестве закутки каждый раз, когда элемент в GridView будет нажат.
Если вы запустите приложение и щелкните любой элемент в сетке, в нижней части экрана появится сообщение. Обратите внимание, что вы можете использовать один и тот же код для прослушивания событий щелчка по элементам внутри ListView .
7. Расширение ArrayAdapter
ArrayAdapter может обрабатывать только один виджет TextView внутри макета создаваемых им объектов View . Чтобы расширить свои возможности, вы должны расширить его. Однако прежде чем мы это сделаем, давайте создадим несколько более сложный набор данных.
Вместо строк, скажем, наш набор данных содержит объекты следующего класса:
Это набор данных, который мы будем использовать:
Как вы можете видеть, класс Cheese содержит два поля, name и description . Чтобы отображать оба поля в списках или сетках, макет элементов должен содержать два виджета TextView .
Создайте новый XML-файл макета и назовите его custom_item.xml. Добавьте в него виджеты Large text и Small text. Установите атрибут id первого виджета на имя cheese_name, а второй — на cheese_description. Содержимое XML-файла макета должно выглядеть следующим образом:
ArrayAdapter также должен иметь возможность обрабатывать два виджета TextView . Измените свою деятельность, создайте новый анонимный класс, который расширяет класс ArrayAdapter и переопределяет его метод getView() . Убедитесь, что вы передаете массив как аргумент его конструктору.
Внутри метода getView() вы должны использовать параметр position в качестве индекса массива и выбрать элемент в этом индексе.
Второй параметр метода getView() — это то, что позволяет нам повторно использовать объекты View . Если вы проигнорируете это, производительность вашего адаптера будет плохой. Когда метод getView() вызывается в первый раз, convertView имеет значение null . Вы должны инициализировать его, изменяя файл ресурсов, который определяет макет элементов списка. Для этого обратитесь к макету LayoutInflater с помощью метода getLayoutInflater() и вызовите его метод inflate() .
На этом этапе вы можете использовать findViewById() , чтобы получить ссылку на виджеты TextView внутри макета и вызвать их методы setText() для их инициализации с использованием данных из массива.
Наконец, верните convertView , чтобы он мог использоваться для заполнения любого вида адаптера, связанного с адаптером.
8. Использование держателя вида
Метод getView() многократно вызывается видом адаптера для заполнения. Поэтому вы должны попытаться свести к минимуму количество операций, которые вы в нем выполняете.
На предыдущем шаге вы могли заметить, что, хотя мы убедились, что макет элементов списка заполняется только один раз, метод findViewById() , который потребляет много циклов процессора, вызывается каждый раз, когда метод вызывается getView() .
Чтобы избежать этого и улучшить производительность представления адаптера, нам нужно сохранить результаты метода findViewById() внутри объекта convertView . Для этого мы можем использовать объект view holder, который представляет собой не что иное, как объект класса, который может хранить виджеты, присутствующие в макете.
Поскольку в макете есть два виджета TextView , класс владельца представления должен также иметь два виджета TextView . Я назвал класс ViewHolder.
В методе getView() после раздувания макета вы можете теперь инициализировать объект держателя вида с помощью метода findViewById() .
Чтобы сохранить объект-держатель вида в convertView , используйте его метод setTag() .
И теперь, каждый раз, когда вызывается getView() , вы можете получить объект держателя вида из convertView с помощью метода getTag() и обновить виджеты TextView внутри него, используя их методы setText() .
Если вы запустите приложение сейчас, вы увидите, что GridView отображает две строки текста в каждой ячейке.
Заключение
В этом уроке вы узнали, как создать адаптер и использовать его для заполнения различных видов адаптеров. Вы также узнали, как создать свой собственный адаптер. Хотя мы ориентируемся только на классы ArrayAdapter , ListView и GridView , вы можете использовать те же методы для других адаптеров и адаптеров, которые предлагает Android SDK.
Android Support Library включает в себя класс RecyclerView . Он очень похож на вид адаптера, но не является подклассом класса AdapterView . Вы должны использовать его, если хотите создать более сложные списки, особенно те, которые используют несколько файлов макета для своих элементов. Чтобы узнать больше об этом, вы можете обратиться к этому учебнику Envato Tuts +.
Чтобы узнать больше о классе AdapterView и его подклассах, вы можете обратиться к его документации.
Источник
Using an ArrayAdapter with ListView
In Android development, any time we want to show a vertical list of scrollable items we will use a ListView which has data populated using an Adapter . The simplest adapter to use is called an ArrayAdapter because the adapter converts an ArrayList of objects into View items loaded into the ListView container.
The ArrayAdapter fits in between an ArrayList (data source) and the ListView (visual representation) and configures two aspects:
- Which array to use as the data source for the list
- How to convert any given item in the array into a corresponding View object
Note as shown above that there are other data sources besides an ArrayAdapter such as the CursorAdapter which instead binds directly to a result set from a Local SQLite Database.
When using an adapter and a ListView , we need to make sure to understand how view recycling works.
When your ListView is connected to an adapter, the adapter will instantiate rows until the ListView has been fully populated with enough items to fill the full height of the screen. At that point, no additional row items are created in memory.
Instead, as the user scrolls through the list, items that leave the screen are kept in memory for later use and then every new row that enters the screen reuses an older row kept around in memory. In this way, even for a list of 1000 items, only
7 item view rows are ever instantiated or held in memory. Here is a visual overview of recycling:
Here is another related diagram on view recycling:
Refer to this ListView guide for another look at how this works to optimize the performance of your lists. Be sure to check out this Udacity video on view recycling as well. If you wish to evaluate how fast your ListView is rendering, check out the Profiling GPU tool, which provides a graphical way of visualizing the layout performance.
To use a basic ArrayAdapter , you just need to initialize the adapter and attach the adapter to the ListView. First, we initialize the adapter:
The ArrayAdapter requires a declaration of the type of the item to be converted to a View (a String in this case) and then accepts three arguments: context (activity instance), XML item layout, and the array of data. Note that we’ve chosen simple_list_item_1.xml which is a simple TextView as the layout for each of the items.
Now, we just need to connect this adapter to a ListView to be populated:
By default, this will now convert each item in the data array into a view by calling toString on the item and then assigning the result as the value of a TextView (simple_list_item_1.xml) that is displayed as the row for that data item. If the app requires a more complex translation between item and View then we need to create a custom ArrayAdapter instead.
When we want to display a series of items from a list using a custom representation of the items, we need to use our own custom XML layout for each item. To do this, we need to create our own custom ArrayAdapter class. See this repo for the source code. First, we often need to define a model to represent the data within each list item.
Given a Java object that has certain fields defined such as a User class:
We can create a custom ListView of User objects by subclassing ArrayAdapter to describe how to translate the object into a view within that class and then using it like any other adapter.
Next, we need to create an XML layout that represents the view template for each item in res/layout/item_user.xml :
Next, we need to define the adapter to describe the process of converting the Java object to a View (in the getView method). The naive approach to this (without any view caching) looks like the following:
That adapter has a constructor and a getView() method to describe the translation between the data item and the View to display.
getView() is the method that returns the actual view used as a row within the ListView at a particular position. Another method used is getItem() which is already present in the ArrayAdapter class and its task is to simply get the data item associated with the specified position in the data set which is associated with that ArrayAdapter .
Now, we can use that adapter in the Activity to display an array of items into the ListView:
At this point, the ListView is now successfully bound to the users array data.
Once the adapter is attached, items will automatically be populated into the ListView based on the contents of the array. You can add new items to the adapter at any time with:
which will append the new items to the list. You can also clear the entire list at any time with:
Using the adapter now, you can add, remove and modify users and the items within the ListView will automatically reflect any changes.
In order to create model instances, you will likely be loading the data from an external source (i.e database or REST JSON API), so you should create two additional methods in each model to allow for construction of a list or a singular item if the data is coming from a JSON API:
For more details, check out our guide on converting JSON into a model. If you are not using a JSON source for your data, you can safely skip this step.
Within a ListView , we can easily attach event listeners onto any of the views that are item position-aware with:
You can also similarly pass an entire object through a tag as well as shown here:
With this approach, you can easily access data as needed from within any event handlers.
To improve performance, we should modify the custom adapter by applying the ViewHolder pattern which speeds up the population of the ListView considerably by caching view lookups for smoother, faster item loading:
In this example, we also have a private static class called ViewHolder . Making calls to findViewById() can be slow in practice, and if your adapter has to call it for each View in your row for every single row then you can often run into performance issues. What the ViewHolder class does is cache the call to findViewById() . Once your ListView has reached the max amount of rows it can display on a screen, Android is smart enough to begin recycling those row Views. We check if a View is recycled with if (convertView == null) . If it is not null then we have a recycled View and can just change its values, otherwise, we need to create a new row View. The magic behind this is the setTag() method which lets us attach an arbitrary object onto a View object, which is how we save the already inflated View for future reuse.
Customizing Android ListView Rows by Subclassing describes a strategy for obtaining instances of child views using a similar approach as a ViewHolder but without the explicit ViewHolder subclass.
Источник