Адаптеры
В Android часто используются адаптеры. Если говорить в общих чертах, то адаптеры упрощают связывание данных с элементом управления. Адаптеры используются при работе с виджетами, которые дополняют android.widget.AdapterView: ListView, ExpandableListView, GridView, Spinner, Gallery, а также в активности ListActivity и др. Сам AdapterView дополняет android.widget.ViewGroup.
Итак, у нас есть набор объектов и есть компонент View. Назначение адаптера заключается в том, чтобы предоставлять дочерние виды для контейнера. Адаптер берет данные и метаданные определенного контейнера и строит каждый дочерний вид. Например, мы формируем пункты списка (массив строк) и передаём его списку ListView.
Вы что-нибудь поняли? Мой кот тоже ничего не понял. Попробуем объяснить по-другому. Что такое вообще адаптер? Это переходник между двумя какими-то предметами. Допустим, между питьевой водой и котом требуется адаптер в виде крана.
В данном случае адаптер спроектирован плохо, приходится изворачиваться.
Однако вернёмся к Android. В приложениях очень часто используется список на основе ListView. Сам список состоит из множества элементов TextView, которые идут друг за другом. Но их количество будет зависеть от того, чтобы мы хотим отобразить. Если нам нужны дни недели, то достаточно семи элементов, если месяцы, то уже двенадцать, ну а если нам нужны имена котов в Кот д’Ивуаре, то счёт пойдет на сотни. Короче говоря, нам нужно составить данные, например, в виде массива и скормить его списку. Адаптер этим и занимается. Он берёт по порядку предоставленные данные и размещает их в списке по порядку. При этом адаптер на лету создаёт нужные компоненты TextView и помещает в него приготовленный текст. Данные могут быть находиться не только в массиве, но и в базе данных. Для такого случая используется другой адаптер. А также вы можете придумать свой адаптер. Существуют уже готовые адаптеры на самые распространённые случаи и их предназначение можно определить по именам. Например, ArrayAdapter использует массив, а CursorAdapter работает с объектом Cursor, используемый в базах данных.
Готовые адаптеры
Все адаптеры, содержащиеся в Android, дополняют базовый адаптер BaseAdapter. Вот список готовых адаптеров:
- ArrayAdapter — предназначен для работы с ListView. Данные представлены в виде массива, которые размещаются в отдельных элементах TextView
- ListAdapter — адаптер между ListView и данными. Строго говоря, это класс-интерфейс, который можно использовать и в ArrayAdapter и в SimpleAdapter и т.д.
- SpinnerAdapter — адаптер для связки данных с элементом Spinner. Это тоже интерфейс, как ListAdapter и работает по схожему принципу
- SimpleAdapter — адаптер, позволяющий заполнить данными список более сложной структуры, например, два текста в одной строке списка.
- SimpleCursorAdapter — дополняет ResourceCursorAdapter и создаёт компоненты TextView/ImageView из столбцов, содержащихся в курсоре. Компоненты определяются в ресурсах
- CursorAdapter — предназначен для работы с ListView, предоставляет данные для списка через курсор, который должен иметь колонку с именем «_id»
- ResourceCursorAdapter — этот адаптер дополняет CursorAdapter и может создавать виды из ресурсов
- HeaderViewListAdapter — расширенный вариант ListAdapter, когда ListView имеет заголовки.
- WrapperListAdapter — еще один адаптер для списков.
BaseAdapter
Стандартные адаптеры не всегда покрывают потребности программиста. Если вам нужен свой собственный адаптер, то в Android есть абстрактный класс BaseAdapter, который можно расширить. Собственный адаптер необходим в тех случаях, когда требуется специальное управление данными или дополнительный контроль над отображением дочерних представлений. Кроме того, вы можете предусмотреть в своём адаптере элементы кэширования для повышения производительности работы.
Пример использования адаптере на основе BaseAdapter можно увидеть при создании GridView с картинками и в других примерах.
У BaseAdapter есть несколько методов, которые следует переопределить. Например, метод getCount() позволяет узнать количество выводимых объектов.
Другой важный метод адаптера — getView(), который отвечает за создание отдельных элементов списка. Он вызывается для каждого элемента списка, чтобы определить, какие данные нужно отобразить. Метод getVew() содержит параметр convertView, который позволяет использовать заново уже существующий элемент списка, который не отображается, т.к. пользователь пролистнул его с видимой части дисплея. Если convertView не пустой, он может быть использован заново, чтобы не грузить разметку списка. Подобный подход способствует увеличению производительности.
Метод getView() возвращает View, который фактически является контейнером ViewGroup и содержит в себе другие компоненты, например, ImageView или TextView.
На сайте представлены (будут представлены) практически все примеры с адаптерами. Оставайтесь на связи!
Источник
Урок 22. Android Data Binding. Adapter. Conversion.
В этом уроке разберем, как можно расширить возможности биндинга с помощью Binding Adapter и Binding Conversion.
Полный список уроков курса:
Binding Adapter
Android Data Binding предоставляет нам возможность вмешиваться в процесс биндинга и самим определять действие, которое будет выполнено при передаче нового значения в какой-либо атрибут View.
Рассмотрим пример, как биндингом можно сделать загрузку изображений из Internet.
Предположим, что у объекта Employee есть поле avatarUrl, в котором находится ссылка на картинку. Используем это поле в биндинге ImageView.
Для ImageView мы добавили свой кастомный атрибут url и туда будем передавать значение из avatarUrl.
Если сейчас попытаться запустить приложение, то получим ошибку: Cannot find the setter for attribute ‘app:url’ with parameter type java.lang.String on android.widget.ImageView.
Биндинг сообщает, что не может найти setter для атрибута app:url. Давайте создадим такой setter.
Создаем статический public метод в любом классе. Можно выделить под это отдельный класс BindingAdapters, например.
В аннотации BindingAdapter указываем атрибут, для которого хотим сделать setter. Первым параметром метода идет ImageView, с которым биндинг будет работать. А вторым параметром придет значение, которое придет атрибут из employee.avatarUrl.
Этот метод будет вызван, когда для app:url будет выполняться биндинг. Мы используем Picasso, чтобы подгрузить картинку в ImageView.
Setter может работать сразу с несколькими атрибутами. Например, добавим drawable, который должен отображаться в случае, если Picasso не удалось загрузить изображение.
Добавляем атрибут errorImage и передаем туда drawable.
В аннотации пишем оба своих атрибута, и в параметрах метода указываем, что ожидаем String и Drawable. В Picasso добавляем использование Darawable в методе error.
Conversion
Conversion удобно использовать, если View ожидает один тип данных, а у вас есть другой, и вам надо выполнить конвертацию.
Рассмотрим пример со списком хобби работника:
Hobby — это отдельный класс с полем name.
Мы хотим выводить список хобби одной строкой в TextView.
Если мы сделаем так:
То получим ошибку: Cannot find the setter for attribute ‘android:text’ with parameter type java.util.List on android.widget.TextView
Биндинг сообщает, что не может поместить List в атрибут android:text. Нам надо научить биндинг конвертировать List в String.
Напишем конвертер. Для этого нужен статический метод с аннотацией BindingConversion. На вход этот метод будет принимать List . А на выходе метод должен вернуть String, чтобы TextView смог это значение принять.
В методе просто все значения из списка помещаем в одну строку.
Биндинг найдет этот конвертер, преобразует список в строку и поместит ее в TextView.
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Android Adapters (and AdapterViews)
by Jim White | Jun 16, 2014
Android’s Adapter is described in the API documentation, as “a bridge between an AdapterView and the underlying data for that view” (see here). An AdapterView is a group of widgets (aka view) components in Android that include the ListView, Spinner, and GridView. In general, these are the widgets that provide the selecting capability in the user interface (read about AdapterView widgets here). What is not mentioned in the documentation is that the AdapterView also provides the layout of the underlying data for the view. The AdapterView really brings together the data and the layout (potentially in a complex collection of views) for each of the rows that make up the AdapterView.
So Many Adapters to Choose From
The Adapter is actually an interface. When you dig deeper into the API, you realize there are quite a few Adapter interfaces, abstract classes and implementing classes.
Which one to use and under what circumstances? I think the depth and width of the Adapter hierarch tends to confuse many beginning Android developers and my hope is that this post can help clarify the choice for developers.
The Interfaces
All Adapters ultimately implement the Adapter interface. However, the two sub-interfaces of Adapter are ListAdapter and SpinnerAdapter. These adapter interfaces define the adapter for ListViews and SpinnerViews (see diagram below) – the two main types of AdapterViews. So, in general, when you are using a ListView (to include GridViews) in your user interface, you are going to need an Adapter that implements (directly or indirectly) the ListAdapter. When you are using a Spinner, you are going to need an Adapter that implements (directly or indirectly) the SpinnerAdapter. Pretty simple and straightforward so far.
Adapter View Hierarchy
The BaseAdapter
The source of much confusion comes from the fact that the BaseAdapter is the abstract class that implements the interfaces – all of them! In implements ListAdapter, SpinnerAdapter and Adatper! Java does not allow for multiple inheritance among classes, but a class can implement multiple interfaces which is exactly what BaseAdapter does.
Adapter interface defines 10 methods that must be implemented by the developer. BaseAdapter is provided as a convenience to Android developers. Rather than creating a class the implements Adapter, SpinnerAdapter or ListAdapter, just extend BaseAdapter and implement the specialized methods for either a ListView or Spinner. What’s more, the BaseAdapter already provides common implementations for many of the interfaces so you don’t have to override these unless there is a specific need.
At a minimum, you will need to implement four methods. These four methods are called by Android to build your AdapterView and to return the correct information when one of the items in the AdapterView is selected.
- getCount( ): indicates to Android how many items (or rows) are in the data set that will be presented in the AdapterView.
- getItem(int pos): get the data item associated with the item (or row) from the AdapterView passed as a parameter to the method. This method will be used by Android to fetch the appropriate data to build the item/row in the AdapterView.
- getItemId(int pos): This method returns the data set’s id for a item/row position of the AdapterView. Typically, the data set id matches the AdapterView rows so this method just returns the same value.
- getView(int position, View convertView, ViewGroup parent): This method creates the View (which may be a single View component like a TextView or a complex set of widgets in a layout) that displays the data for the specified (by position) item/row in the AdapterView.
Beyond the position parameter, the getView( ) method gets passed two other important parameters. The convertView parameter allows a previously created View to be reused. When the AdapterView is first created, this argument will be null. On subsequent calls to build/display the AdapterView, the View component used to display the item/row is supplied back to this method so that you can either reuse it or discard it depending on what needs to be displayed. The last parameter to the getView( ) method is the parent View (usually the AdapterView) to which the View for the item/row is attached.
As an example, say you had an ArrayList of golf course objects (your data set) you want to display in a ListView (your AdapterView). For each of the golf course objects, you want to display a layout (the View) containing a checkbox, the course name, and par score for each golf course object.
The BaseAdapter to pull off this implementation looks something like the following code.
In the example code above, the getView( ) method programmatically builds the view that represents each course in the ListView display. However, you could use an XML layout file to help construct the View.
Also, note that the adapter (CourseAdapter above) is not directly tied to the type of AdapterView. This adapter could be assigned to a ListView…
… or Spinner with equal ease.
The Other Adapters
If you look again at the Adapter hierarchy, you’ll see lots of other adapters. So what is their purpose? When do you use the BaseAdapter and when do you use one of these other adapters? In general, these other adapters provide even more convenience, but may be constraining depending on your view and data display needs.
ArrayAdapter
The ArrayAdapter tries to make even the BaseAdapter simpler. Out of the box, the ArrayAdapter’s data set is always an array (or ArrayList) of objects. Each of the objects in the array is presented by a single TextView widget, by default. The text of the TextView displays the toString() of each element in the array. If these constrains work for you and your user interface, then Using the ArrayAdapter is extremely simple. You don’t have to override any methods since the class provides everything built in. You simply create an instance of the ArrayAdapter and give it to the AdapterView.
Returning to the list of golf course example, here is the code in an activity to create an ArrayAdapter for the display of golf courses in a ListView (although it would also work the same for a spinner).
The reference to android.R.layout.simple_list_item_1 is a built-in Android layout (shown below) that provides the TextView for each of the objects in the array.
Above is the ListView’s display given the toString() method for Course below.
You can customize the ArrayAdapter and do more of the work yourself, but the idea is that the ArrayAdapter provides a quick, easy, and simple to use Adapter when you simply need to display a view of strings that represent a collection of objects.
SimpleAdapter
SimpleAdatper’s data set is an ArrayList of Maps. Each Map in the ArrayList contains the data to be displayed for a row in the AdapterView. Unlike the other adapters, the data set is expected to be static – that is, it is not changing.
SimpleAdapter’s data structure
As with ArrayAdapter, the SimpleAdapter typically does not require you to build your own class and override methods. You use SimpleAdapter’s constructor to build an instance and attach it to the AdapterView. Below, the golf course example is used one more time to create a ListView displaying the list of course data.
The SimpleAdapter constructor can seem a bit unwieldy. It takes quite a few arguments.
- The context of the AdapterView
- The List of Maps data structure
- The resource ID of the layout for each row. In the example above, the resource id (android.R.layout.simple_list_item_2) is to an Android built-in layout with two TextView widgets that is covered below.
- An array of the key names (the “from” array) that are in the Map data set objects.
- An array of resource ids (the “to” array) for the widgets that will display the Map value for each associated key in the “from” array.
The built-in simple_list_item_2 layout (shown below) is perfect for the display of the course data as it conveniently provides for two TextView widgets. However, you could provide your own layout to customize the display of each row.
The SimpleAdapter allows the display of for more and varied data by default, whereas the ArrayAdapter works on a simple toString() representation of an array of objects. Again, you can extend SimpleAdapter, but at the cost of more work – which often leads you back to implementing one of the Adapter interfaces.
CursorAdapter (& SimpleCursorAdapter)
The CursorAdapter (and its subclass the SimpleCursorAdapter) utilizes an Android Cursor (often from an SQLite database or ContentProvider) to provide the data set for the Adapter. This last of the BaseAdapter sub-classes requires more time/space to cover than is reasonable for this post. For a good example, see here. The CursorAdapter provides a means for AdapterViews to “scroll” through a potentially very dynamic data set.
Wrap Up
Adapters bring the layout of data and the data itself to AdapterViews like ListView and Spinner in Android. Once you understand the hierarchy of Adapter and AdapterView types, selecting and using an Adapter for your user interface is more straightforward. Give us a call if Intertech Training or Consulting can help make mobile development more straightforward for you.
Источник