Адаптеры (BaseAdapter)

Материал из AOW

Перейти к: навигация, поиск

В Android часто используются адаптеры. Если говорить в общих чертах, то адаптеры упрощают связывание данных с элементом управления. Адаптеры используются при работе с виджетами, которые дополняют android.widget.AdapterView: ListView, GridView, Spinner, Gallery. Сам AdapterView дополняет android.widget.ViewGroup.

Назначение адаптера заключается в том, чтобы предоставлять дочерние виды для контейнера. Адаптер берет данные и метаданные определенного контейнера и строит каждый дочерний вид. Например, мы формируем пункты списка (массив строк) и передаём его списку ListView.

Содержание

Адаптеры

Адаптер – мост между набором данных и объектом, использующим эти данные. Также адаптер отвечает за создание View-компонента для каждой единицы данных из набора.

Схема java-иерархии интерфейсов и классов адаптеров. В скобках указан тип: I – это интерфейс, AC – абстрактный класс, C – класс. Линии – это наследование. Читать следует сверху вниз.

Файл:Adapter_android_01.jpg

Давайте по порядку смотреть, зачем оно все нужно.

Интерфейс Adapter. Описывает базовые методы, которые должны содержать адаптеры: getCount, getItem, getView и пр.

Интерфейс ListAdapter. Этот интерфейс должен быть реализован адаптером, который будет использован в ListView (метод setAdapter). Содержит описание методов для работы с разделителями(separator) списка.

Интерфейс SpinnerAdapter. Адаптеры, реализующие этот интерфейс, используются для построения Spinner(выпадающий список или drop-down). Содержит метод getDropDownView, который возвращает элемент выпадающего списка. На офиц.сайте есть пример использования.

Интерфейс WrapperListAdapter. Адаптеры, наследующие этот интерфейс используются для работы с вложенными адаптерами. Содержит метод getWrappedAdapter, который позволяет вытащить из основного адаптера вложенный. Чуть дальше поясню.

  • Класс HeaderViewListAdapter. Готовый адаптер для работы с Header и Footer. Внутри себя содержит еще один адаптер (ListAdapter), который можно достать с помощью выше рассмотренного метода getWrappedAdapter из интерфейса WrapperListAdapter.
  • Абстрактный класс BaseAdapter. Содержит немного своих методов и реализует методы интерфейсов, которые наследует, но не все. Своим наследникам оставляет на обязательную реализацию методы: getView, getItemId, getItem, getCount из ListAdapter. Т.е. если хотите создать свой адаптер – это класс вам подходит.
  • Класс ArrayAdapter<T>. Готовый адаптер, который мы уже использовали. Принимает на вход список или массив объектов, перебирает его и вставляет строковое значение в указанный TextView. Кроме наследуемых методов содержит методы по работе с коллекцией данных – add, insert, remove, sort, clear и метод setDropDownViewResource для задания layout-ресурса для отображения пунктов выпадающего списка.
  • Класс SimpleAdapter. Также готовый к использованию адаптер. Принимает на вход список Map-объектов, где каждый Map-объект – это список атрибутов. Кроме этого на вход принимает два массива – from[] и to[]. В to указываем id экранных элементов, а в from имена(key) из объектов Map, значения которых будут вставлены в соответствующие (из from) экранные элементы.

Т.е. SimpleAdapter – это расширенный ArrayAdapter. Если вы делаете ListView и у вас каждый пункт списка содержит не один TextView, а несколько, то вы используете SimpleAdapter. Кроме наследуемых методов SimpleAdapter содержит методы по наполнению View-элементов значениями из Map – setViewImage, setViewText, setViewBinder. Т.е. видим, что он умеет работать не только с текстом, но и с изображениями. Метод setViewBinder – отличная штука, позволяет вам написать свой парсер значений из Map в View-элементы и адаптер будет использовать его. Это мы еще детально обсудим в дальнейших уроках.

Также содержит реализацию метода setDropDownViewResource.

  • Абстрактный класс CursorAdapter. Реализует абстрактные методы класса BaseAdapter, содержит свои методы по работе с курсором и оставляет наследникам методы по созданию и наполнению View: newView, bindView.
  • Абстрактный класс ResourceCursorAdapter. Содержит методы по настройке используемых адаптером layout-ресурсов. Реализует метод newView из CursorAdapter.
  • Класс SimpleCursorAdapter. Готовый адаптер, похож, на SimpleAdapter. Только использует не набор объектов Map, а Cursor, т.е. набор строк с полями. Соответственно в массив from[] вы заносите наименования полей, значения которых хотите вытащить в соответствующие View из массива to.

Содержит метод convertToString, который возвращает строковое значение столбца, который задается методом setStringConversionColumn. Либо можно задать свой конвертер методом setCursorToStringConverter и адаптер будет использовать его при вызове convertToString. В этом конвертере вы уже сами реализуете, что он будет возвращать.

Итого мы получили 4 готовых адаптера: HeaderViewListAdapter, ArrayAdapter<T>, SimpleAdapter, SimpleCursorAdapter. Какой из них использовать - решать вам. Если у вас есть массив строк - то, не раздумывая, берете ArrayAdapter. Если работаете с БД и есть курсор, данные из которого надо вывести в список - используете SimpleCursorAdapter.

Если же эти адаптеры вам не подходят, есть набор абстрактных классов и интерфейсов, которые можем наследовать и реализовать в своих классах для создания своего адаптера. Да и готовые адаптеры всегда можно наследовать и сделать свою реализацию методов.

Кроме этой иерархии есть почти аналогичная ей. В ней содержатся адаптеры для работы с деревом – ExpandableListView. Я не буду здесь их расписывать, в целом они похожи на, уже рассмотренные, нами объекты. Но есть разница в том, что здесь данные не одноуровневые, а делятся на группы и элементы.

Файл:Adapter_android_02.jpg

Здесь мы видим один готовый адаптер. SimpleExpandableListAdapter - работает с коллекциями Map.

Готовые адаптеры

Все адаптеры, содержащиеся в Android, дополняют базовый адаптер BaseAdapter. Вот список готовых адаптеров:

  • ArrayAdapter<T> - предназначен для работы с ListView
  • CursorAdapter - также предназначен для работы с ListView, предоставляет данные для списка через курсор
  • SimpleAdapter - очень простой адаптер. Обычно используется для заполнения списка статическими данными (которые могут быть взяты из ресурсов)
  • ResourceCursorAdapter - этот адаптер дополняет CursorAdapter и может создавать виды из ресурсов
  • SimpleCursorAdapter - дополняет ResourceCursorAdapter и создает виды TextView/ImageView из столбцов, содержащихся в курсоре. Виды определяются в ресурсах

ArrayAdapter

ArrayAdapter является простейшим адаптером, который специально предназначен для работы с элементами списка. Создать адаптер этого вида можно так:

// используется системная разметка
ArrayAdapter<String> adapter  =  new  ArrayAdapter<String>( 
    this.android.R.layout.simple_list_item1, new  string[]{"Рыжик", "Барсик", "Мурзик"});

Если посмотреть на исходники файла simple_list_item_1.xml в документации Android SDK, то увидим, что он содержит TextView. В этом коде мы создали адаптер ArrayAdapter, в котором данные элемента TextView представлены в виде строк.

Чтобы код был более читаемым, можно сделать ещё так:

// определяем массив типа String
final String[] catnames = new String[] {
    "Рыжик", "Барсик", "Мурзик"		    
};

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, catnames);

lv.setAdapter(adapt);

Мы вынесли массив строк в отдельную переменную.

Если у нас есть готовый файл ресурсов (массив строк), то можно использовать специальный метод createFromResource(), который может создать ArrayAdapter из ресурсов:

Подготовим массив строк:

<string-array  name="planets"> 
    <item>Меркурий</item> 
    <item>Венера</item> 
    <item>Земля</item> 
    <item>Марс</item> 
    <item>Юпитер</item> 
    <item>Сатурн</item> 
    <item>Уран</item> 
    <item>Нептун</item> 
</string-array> 

Теперь мы можем воспользоваться адаптером:

Spinner spinner = (Spinner) findViewByid(R.id.spinner1); 
adapter = ArrayAdapter.createFromResource(this,
        R.array.planets, android.R.layout.simple_spinner_item); 
adapter.setDropDownViewResource
        (android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

При использовании этого метода вы можете применять локализованные версии, что очень удобно.

Переопределяем адаптер

По умолчанию ArrayAdapter использует метод toString() из объекта массива, чтобы наполнять данными элемент TextView, размещенный внутри указанной разметки. Если вам нужно изменить разметку, применяемую для отображения каждого представления, то можно наследоваться от класса ArrayAdapter, указывая конкретный тип и переопределяя метод getView(), чтобы установить свойства объекта для представлений из разметки.

Метод getView() используется для создания и наполнения данными представления, отображаемого внутри родительского элемента AdapterView (например, ListView), который был привязан к исходному массиву с помощью этого адаптера.

Метод getView() принимает следующие параметры: позицию элемента, на какой он будет выведен, представление, которое обновляется (или null), а также объект ViewGroup, где новое представление поместится. Вызов метода getItem() вернет значение из исходного массива по указанному индексу. В результате метод getView() должен вернуть экземпляр представления, наполненный данными.

public class MyArrayAdapter extends ArrayAdapter<MyClass> {
    int resource;
    public MyArrayAdapter(Context context,
            int _resource,
            List<MyClass> items) {
                super(context, _resource, items);
                resource = _resource;
            }
    
	@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LinearLayout newView;
        MyClass classInstance = getItem(position);
        // TODO Извлечь из переменной classInstance
        // данные для отображения.
        // Inflate a new view if this is not an update.
        if (convertView == null) {
            newView = new LinearLayout(getContext());
            String inflater = Context.LAYOUT_INFLATER_SERVICE;
            LayoutInflater vi = (LayoutInflater)getContext().
                    getSystemService(inflater);
            vi.inflate(resource, newView, true);
	    } else {
            newView = (LinearLayout)convertView;
        }
        // TODO Извлечь Представления для наполнения их данными.
        // TODO Наполнить Представления свойствами из полученного объекта.
        return newView;
    }
}

Чтобы применить адаптер к классу, основанному на AdapterView, необходимо вызвать из представления метод setAdapter следующим образом:

ArrayList<String> myStringArray = new ArrayList<String>();
ArrayAdapter<String> myAdapterInstance;
int layoutID = android.R.layout.simple_list_item_1;
myAdapterInstance = new ArrayAdapter<String>(this, layoutID , 
myStringArray);
myListView.setAdapter(myAdapterInstance);

В этом фрагменте представлен наиболее простой случай, когда привязка идет к массиву, состоящему из строк, и каждый элемент ListView являет собой одиночный объект TextView.

SimpleCursorAdapter

Класс SimpleCursorAdapter позволяет назначать данные Курсора, используемые источником данных, для представлений. Устарел, не использовать в новых проектах.

Конструктор этого класса получает следующие параметры:

  • параметр Context, в котором выполняется компонент ListView или ему подобный
  • ID ресурса для разметки, который используется для отображения каждого элемента в ListView
  • класс Cursor, который обеспечивает доступ к данным, — этому аргументу можно присвоить значение null, если класс Cursor определяется позже
  • массив String, включающий отображаемые названия столбцов
  • массив типа int, включающий идентификаторы ID соответствующих ресурсов GUI

Класс SimpleCursorAdapter — это подкласс класса CursorAdapter, который был разработан для облечения отображения столбцов класса Cursor непосредственно на компоненты TextViews или ImagesView, определенные в XML-разметке. Для создания класса SimpleCursorAdapter сначала определите массивы, включающие имена столбцов, для отображения на компоненты GUI. Также следует определить ID ресурсов для компонентов GUI, которые отображают данные из именованных столбцов. В коде создается массив String, показывающий, что может отображаться лишь именованный столбец. Затем создается параллельный массив типа int, содержащий ID ресурсов для соответствующих компонентов GUI. Потом создается класс SimpleCursorAdapter.

BaseAdapter

Стандартные адаптеры не всегда покрывают потребности программиста. Если вам нужны более навороченные адаптеры, то для вас в Android есть абстрактный класс BaseAdapter, который вы можете добавить к собственному адаптеру.

Личные инструменты

Разработка веб-сайтов, автоматизация.
По всем вопросам обращайтесь по телефонам:

+7 495 640 29 90
http://artofweb.ru