Заполнение spinner из базы данных через Cursor Loader

Понадобилось мне тут как-то заполнить Spinner из базы данных. Поскольку, даже с собственной базой приложения я работаю через контент-провайдер, прикрутил к спиннеру SimpleCursorAdapter и заполнял его через CursorLoader. Все оказалось достаточно просто. Для начала, добавляем к классу нашей Activity реализацию интерфейса LoaderCallbacks. Поскольку CorsorLoader используется для асинхронных запросов к контент-провайдерам, методы интерфейса LoaderCallbacks будут вызываться по окончании запросов:

public class MainActivity extends Activity implements LoaderCallbacks;

Теперь, в нужном нам методе, например в OnCreate(), получаем spinner, который будем заполнять из БД, создаем для него SimpleCursorAdapter, настраиваем его, присваиваем адаптер спиннеру, и запускаем запрос к БД

	view = inflater.inflate(R.layout.activity_main, null); // получаем view нашей activity

	// Получаем спиннер:
	spin = (Spinner) view.findViewById(R.id.spinner1);

	// Создаем адаптер запроса из БД данных для спиннера
	spinAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, null,
			new String[] {"name"}, new int[] {android.R.id.text1}, 0);

	// Дополнительно настраиваем адаптер
	spinAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

	// Устанавливаем спиннеру адаптер
	spin.setAdapter(spinAdapter);

	// создаем лоадер для чтения данных
	this.getSupportLoaderManager().initLoader(0, null, this);

Здесь применяется конструктор SimpleCursorAdapter для применения CursorLoader, так, как агитирует нас великий google, а именно, такая его реализация:

SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)

Т.е. передаем конструктору контекст, затем — компоновку элемента списка для адаптера (я использовал стандартную гугловскую android.R.layout.simple_spinner_item). Вместо курсора передаем null, ибо CursorLoader по окончании выборки сам создаст нам курсор.

Далее — передаем строковый массив всего с одним элементом — названием колонки в таблице базы данных, откуда в spinner попадут данные (у меня это колонка «name«).

Следующий параметр — массив int[], который содержит всего один элемент — идентификатор текстового поля в компоновке элемента списка. Поскольку я использовал в качестве компоновки элемента стандартную android.R.layout.simple_spinner_item, она содержит всего одно текстовое поле с идентификатором android.R.id.text1, вот его мы в массиве и передаем.

И последний, интересный параметр int flags — это индекс CursorLoader-а. Индекс применяется, если одновременно используется больше одного лоадера, чтобы запустить несколько запросов и и при их завершении разобраться, от какого из них пришел Callback-вызов. Если CursorLoader используется всего один — тут может быть любая цифра.

Теперь осталось только реализовать методы интерфейса LoaderCallbacks:

////////////////////////////////////////////////////////////////////////////////////
// Обратные вызовы интерфейса LoaderCallbacks
////////////////////////////////////////////////////////////////////////////////////
	@Override
	public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
		// Готовим колонки и условие
		cols = new String[] { "_id", "name" };

		// создаем и возвращаем настроенный лоадер поиска
		return new CursorLoader(this, URI, cols, null, null, null);
	}

	// обработчик окончания выборки из БД
	@Override
	public void onLoadFinished(Loader arg0, Cursor arg1) {
		// Устанавливаем курсор в адаптер
		spinAdapter.swapCursor(arg1);
		break;
	}

	// Этот метод нам без надобности
	@Override
	public void onLoaderReset(Loader arg0) {
	}

Метод onCreateLoader вызывается при создании CursorLoader-а. В нем, если у нас всего один лоадер, создаем новый CursorLoader для запроса данных у контент-провайдера. Для этого, конструктору CursorLoader передаем следующие параметры: контекст, Uri контент-провайдера.

Далее — массив запрашиваемых колонок. Нам нужна колонка «name«, однако обязательно нужно добавить еще и колонку «_id«, иначе программа вывалится с ошибкой — SimpleCursorAdapter использует эту колонку для своих нужд.

Остальные поля — selection (условия запроса), массив String[] selectionArgs, для параметров условия, и строка sortOrder, для указания сортировки. Я эти поля не использовал, и просто поставил null.

Теперь, CursorLoader создан, возвращаем его через return и выборка понеслась 🙂 Теперь, следующим будет вызов будет метода onLoadFinished, когда выборка закончится.

Метод onLoadFinished вызывается, когда закончится выборка данных из базы данных. При этом, в метод передается CursorLoader как arg0 и непосредственно сам курсор, как arg1. Теперь достаточно просто вызвать метод swapCursor() адаптера, прикрученного к спиннеру и передать в качестве параметра только что полученный курсор. Вуаля — спиннер заполнился необходимыми нам данными.

Отдельно отмечу, что если используется несколько лоадеров, по завершении выборки каждого из них будет вызываться этот же самый метод. И чтобы отличить их вызовы друг от друга, можно использовать идентификатор, который применялся при создании SimpleCursorAdapter-а, в качестве последнего параметра. Получить этот идентификатор можно так: arg0.getId()

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *