Android studio cursor get

Cursor

Изучим объект Cursor. Не путайте его с курсором мыши, который бегает у вас на экране.

Работа с курсором

  • Курсор — это набор строк в табличном виде
  • Для доступа курсора вы должны использовать метод moveToFirst(), так как курсор размещается перед первой строкой
  • Вы должны знать названия столбцов
  • Вы должны знать типы столбцов
  • Все методы доступа к массивам основываются на номере столбца, поэтому сначала нужно преобразовать название столбца в номер столбца
  • Курсор является случайным (random cursor) — вы можете переходить вперед, назад и со строки на строку
  • Поскольку курсор является случайным, у него можно запрашивать количество строк (row count)

Класс Cursor содержит немало возможностей для навигации (но не ограничивается только ими):

  • moveToFirst() — перемещает курсор на первую строку в результате запроса;
  • moveToNext() — перемещает курсор на следующую строку;
  • moveToLast() — перемещает курсор на последнюю строку;
  • moveToPrevious() — перемещает курсор на предыдущую строку;
  • getCount() — возвращает количество строк в результирующем наборе данных;
  • getColumnIndexOrThrow() — возвращает индекс для столбца с указанным именем (выбрасывает исключение, если столбец с таким именем не существует);
  • getColumnName() — возвращает имя столбца с указанным индексом;
  • getColumnNames() — возвращает массив строк, содержащий имена всех столбцов в объекте Cursor;
  • moveToPosition() — перемещает курсор на указанную строку;
  • getPosition() — возвращает текущую позицию курсора

Также Android предоставляет следующие методы:

  • isBeforeFirst()
  • isAfterLast() — полезный метод, сигнализирующий о достижении конца запроса. Используется в циклах
  • isClosed()

И другие методы, о которых можно узнать в документации или из примеров.

Курсор обязательно следует закрывать методом close() для освобождения памяти.

Наглядно о курсорах

Чтобы было проще понять, что такое курсоры, представляйте их в виде таблицы. Пусть у нас есть таблица из столбцов: _id (идентификатор) и catname (имя котов). Допустим, мы ввели в базу имена четырех котов и таблица базы данных выглядит таким образом:

_id catname
1 Мурзик
2 Васька
3 Барсик
4 Рыжик

Как было сказано выше, при работе с курсорами необходимо вызвать метод moveToFirst() (перейти к первой строке), после чего таблица будет выглядеть следующим образом:

_id catname
1 Мурзик
2 Васька
3 Барсик
4 Рыжик

Как видите, после вызова метода первая строчка таблицы подсвечена. Именно данные этой строки и содержит сейчас курсор. Можно проверить следующим образом. Добавим новую кнопку в проект и напишем код:

На первой строке содержатся данные 1, Мурзик. Мы не знаем, как хранятся данные в курсоре, но нам это и не нужно. С помощью метода getColumnIndex() с указанием имени колонки мы можем извлечь данные, которые хранятся в них.

Теперь вызовем метод moveToNext() (перейти к следующей строке). Таблица будет выглядеть уже так:

_id catname
1 Мурзик
2 Васька
3 Барсик
4 Рыжик

Код для проверки:

Если вызвать метод moveToNext() ещё раз, то переместимся на третью позицию. А теперь представьте ситуацию, что у нас в базе более ста котов, и чтобы узнать имя 85-го кота, нам придётся 85 раз вызывать метод. Не удобно. К счастью, есть метод moveToPosition() (перейти в позицию), в котором сразу можно указать нужную строку (отсчет идет от 0):

А таблица выглядит уже так:

_id catname
1 Мурзик
2 Васька
3 Барсик
4 Рыжик

Надеюсь, вы поняли общий принцип работы с курсором. Теперь вы можете понять, как выглядит курсор после вызова метода moveToLast() (перейти на последнюю запись).

Если нам надо получить имена всех котов из таблицы базы данных, то нужно последовательно вызывать методы moveToNext(). Это проще сделать через цикл. Условием для остановки цикла является проверка возвращаемого значения метода. Если вернётся значение false, значит мы дошли до конца таблицы. В данном случае не нужно вызывать метод moveToFirst(), чтобы не пропустить первую запись:

Цикл можно переписать по другому. Метод isAfterLast() возвращает true, когда курсор с последней записи пытается переместиться в никуда. А пока курсор возвращает false, можно двигать его на следующую позицию. Пример будет выглядеть так:

В примерах мы извлекали строковое значение записи через метод getString():

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

Думаю, приведённых примеров достаточно, чтобы понять с чем едят курсоры. Они совсем не страшные.

Устаревшие методы (deprecated)

Начиная с Android 3.0, многие методы для работы с курсором считаются устаревшими.

  • startManagingCursor()
  • stopManagingCursor()
  • managedQuery()
  • reQuery()

При использовании устаревших методов вы можете получить исключение типа:

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

Наиболее распространён метод managedQuery(), в сети постоянно натыкаюсь на примеры с использованием данного метода.

Читайте также:  Андроид шрифтом times new roman

Обычно, код выглядит следующим образом:

Данный код следует переработать следующим образом:

Метод reQuery() следует заменить на вызов LoaderManager.

Класс CursorLoader и связанный с ним LoaderManager гарантируют, что запросы будут выполняться асинхронно.

Мне пока не приходилось использовать данный приём в своей практике, поэтому просто скопирую из других источников:

  • реализуйте интерфейс в вашем классе как LoaderManager.LoaderCallbacks
  • в методе onCreate() инициализируйте loader как First implement the interface in your class as getLoaderManager().initLoader(0, null, this);
  • вместо reQuery используйте getLoaderManager().restartLoader(0, null, this);
  • переопределите три метода onCreateLoader(), onLoadFinished(), onLoaderReset()

MatrixCursor

Иногда попадаются примеры с использованием класса MatrixCursor. Сам пока не изучал, оставлю вам в качестве домашнего задания. Небольшой пример на память:

Источник

Полный список

— используем SimpleCursorAdapter для построения списка
— добавляем и удаляем записи в списке

Важное замечание! Урок более не актуален, т.к. в нем используются методы, которые гугл объявил устаревшими. Если вы просто зашли посмотреть, как использовать SimpleCursorAdapter, то вместо этого урока рекомендую прочитать Урок 136. Если же вы идете последовательно по урокам, то вполне можно прочесть и понять этот урок, а потом просто акутализируете свои знания в Уроке 136.

После нескольких уроков посвященных SimpleAdapter мы знаем про него достаточно и представляем схему его работы. И теперь нам будет нетрудно усвоить SimpleCursorAdapter. Он отличается тем, что в качестве данных используется не коллекция Map, а Cursor с данными из БД. И в массиве from, соответственно, мы указываем не ключи Map-атрибутов, а наименования полей (столбца) курсора. Значения из этих полей будут сопоставлены указанным View-компонентам из массива to.

Также немного отличается от SimpleAdapter стандартный биндинг и внешний ViewBinder. SimpleCursorAdapter умеет работать с TextView и ImageView компонентами и их производными, а Checkable-производные не воспримет . А при использовании ViewBinder, необходимо реализовать его метод boolean setViewValue (View view, Cursor cursor, int columnIndex). На вход он принимает View-компонент для биндинга, cursor с данными и номер столбца, из которого надо взять данные. Позиция курсора уже установлена в соответствии с позицией пункта списка. Не буду снова расписывать примеры использования, т.к. они будут очень похожи на примеры из предыдущих уроков по SimpleAdapter. Если там все было понятно, то и здесь проблем не должно возникнуть.

Итак, давайте накидаем пример использования SimpleCursorAdapter. Список будет отображать картинку и текст. Также реализуем возможность добавления и удаления данных из списка. Добавлять будем кнопкой, а удалять с помощью контекстного меню.

Project name: P0521_SimpleCursorAdapter
Build Target: Android 2.3.3
Application name: SimpleCursorAdapter
Package name: ru.startandroid.develop.p0521simplecursoradapter
Create Activity: MainActivity

Обычно в уроках я тексты для кнопок и прочего указывал напрямую. Делал я это не со зла, а чтобы не перегружать урок лишней информацией. Но с последними обновлениями Eclipse стал ругаться примерно так: [I18N] Hardcoded string «какой-то текст», should use @string resource. Ошибка не критична и запуску приложения никак не помешает, но некоторых она смущает. Да и действительно, хардкод – это плохо. С этого урока постараюсь следовать правилам хорошего тона и использовать файлы ресурсов. На нашем текущем уровне знаний это не должно стать помехой в понимании и усвоении уроков.

Тут кроме названия приложения я записал тексты для кнопки и контекстного меню

Кнопка для добавления записи и список.

Layout для пункта списка item.xml:

Картинка и текст.

Т.к. SimpleCursorAdapter – это адаптер для работы с данными из БД, то нам нужно эту БД организовать. Чтобы не загромождать MainActivity.java, я вынесу код по работе с БД в отдельный класс DB. Создаем класс DB.java в том же пакете, где и MainActivity.java

Здесь все нам знакомо по прошлым урокам SQLite.

Мы создаем несколько public методов, чтобы Activity могла через них работать с данными:

open – установить соединение
close – закрыть соединение
getAllData – получить курсор со всеми данными из таблицы
addRec – добавить запись
delRec – удалить запись

Это методы-оболочки для работы с БД, которые предоставят MainActivity только те возможности, какие ей нужны.

Вложенный класс DBHelper – для создания и управления БД. В методе onCreate мы создаем таблицу и заполняем ее сгенерированными данными. Метод onUpgrade я оставил пустым, т.к. в этом примере не планирую обновлять версию БД.

Хорошо, что мы создали DB.java. Благодаря ему в MainActivity.java все красиво, прозрачно и удобно. Смотрим код.

В onCreate мы организуем подключение к БД, получаем курсор и просим Activity присмотреть за ним. Теперь при смене Lifecycle-состояний Activity, оно будет менять соответствующим образом состояния курсора. Затем настраиваем биндинг – формируем массивы, которые укажут адаптеру, как сопоставлять данные из курсора и View-компоненты. В R.id.ivImg пойдет значение из поля img, а в R.id.tvText – значение из поля txt. Имена полей мы здесь указываем public-константами класса DB. Далее мы создаем адаптер и настраиваем список на его использование. В конце добавляем контекстное меню к списку.

Читайте также:  Hitman codename 47 для андроид

В методе onButtonClick мы генерируем и добавляем запись в БД и обновляем курсор методом requery, чтобы получить свежие данные из БД.

При создании контекстного меню, в методе onCreateContextMenu, мы добавляем пункт для удаления.

В методе onContextItemSelected мы обрабатываем нажатие пункта контекстного меню. Чтобы получить данные по пункту списка, для которого был совершен вызов контекстного меню, мы используем метод getMenuInfo. Объект AdapterContextMenuInfo содержит данные о View, id и позиции пункта списка. Нам нужно id. Этот id равен значению поля _id для соответствующей записи в курсоре. Мы вызываем метод удаления записи и обновляем курсор.

В методе onDestroy мы закрываем подключение к БД. Это будет происходить при закрытии Activity.

Все сохраняем и запускаем.

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

Мы рассмотрели возможность добавления и удаления записей в списке при использовании SimpleCursorAdapter. Возможность редактирования я рассматривать не стал. Это не особо усложнило бы урок, но сделало бы его больше и размыло бы тему. А я стараюсь делать уроки максимально заточенными под конкретную тему. Для тех, кому интересно редактирование – гугл любезно создал такой пример на официальном сайте — http://developer.android.com/resources/tutorials/notepad/index.html. Мой пример похож на него, так что будет проще разобраться.

Кстати, в этом уроке мы встретили список, в котором id пункта может не совпадать с позицией. Для теста попробуйте повесить обработку нажатия на пункт списка и посмотреть, что позиция – это будет позиция пункта в списке, а id – это идентификатор записи из БД (поле _id). Чтобы это работало, необходимо поле-идентификатор в таблице называть _id, т.к. курсор будет использовать его, как id. Иначе получим ошибку.

На следующем уроке:

— используем SimpleCursorTreeAdapter для построения списка

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Working with Databases in Android

Android architect Adam Stroud presents the Android API for working with databases and explains how to get data from an app to a database and back again.

This chapter is from the book

This chapter is from the book

This chapter is from the book 

The previous chapter introduced the SQLiteOpenHelper and SQLiteDatabase classes and discussed how to create databases. Of course, this is only the first step as a database is not very useful until it contains data and allows software to run queries against that data. This chapter explains how that is done in Android by discussing which Android SDK classes can be used to manipulate a database as well as query a database.

Manipulating Data in Android

The Android SDK contains many classes to support database operations. Along with the classes to support create, read, update, and delete (CRUD) operations, the SDK contains classes to help generate the queries that read the database. Following are the classes introduced in this chapter and a summary of how they are used to work with databases in Android:

SQLiteDatabase: Represents a database in Android. It contains methods to perform standard database CRUD operations as well as control the SQLite database file used by an app.

Cursor: Holds the result set from a query on a database. An app can read the data from a cursor and display it to a user or perform business logic based on the data contained in the cursor.

ContentValues: A key/value store that inserts data into a row of a table. In most cases, the keys map to the column names of the table, and the values are the data to enter into the table.

CursorLoader: Part of the loader framework that handles cursor objects.

LoaderManager: Manages all loaders for an activity or fragment. The LoaderManager contains the API for initializing and resetting a loader that may be used by Android components.

Working with SQL is a vital part of working with databases in Android. In Chapter 2, “An Introduction to SQL,” we saw how SQL is used to both create and upgrade a database. SQL can also be used to read, update, and delete information from a database in Android. The Android SDK provides useful classes to assist in creating SQL statements, while also supporting the use of Java string processing to generate SQL statements.

Читайте также:  Google android one 4pda

Working with SQL in Android involves calling methods on an SQLiteDatabase object. This class contains methods for building SQL statements as well as convenience methods to make issuing SQL statements to the database easy.

In a typical database use case, inserting data into the database is the step that follows creating the database. This makes sense since a database is useful only after it contains data. The steps to create a database were covered in the previous chapter, so this discussion starts with inserting data into a database.

Inserting Rows into a Table

The SQLiteDatabase class contains multiple convenience methods that can be used to perform insert operations. In most cases, one of the following three methods is used to perform an insert operation:

long insert(String table, String nullColumnHack, ContentValues values)

long insertOrThrow(String table, String nullColumnHack, ContentValues values)

long insertWithOnConflict(String table, String nullColumnHack, ContentValues values, int conflictAlgorithm)

Notice that the parameter lists for all the variations of the insert methods contain (as the first three parameters) a String tableName, a String nullColumnHack, and ContentValues values. SQLiteDatabase.insertWithOnConflict() contains a fourth parameter which will be discussed soon. The common three parameters for the insert methods are

String table: Gives the name of the table on which to perform the insert operation. This name needs to be the same as the name given to the table when it was created.

String nullColumnHack: Specifies a column that will be set to null if the ContentValues argument contains no data.

ContentValues values: Contains the data that will be inserted into the table.

ContentValues is a maplike class that matches a value to a String key. It contains multiple overloaded put methods that enforce type safety. Here is a list of the put methods supported by ContentValues:

void put(String key, Byte value)

void put(String key, Integer value)

void put(String key, Float value)

void put(String key, Short value)

void put(String key, byte[] value)

void put(String key, String value)

void put(String key, Double value)

void put(String key, Long value)

void put(String key, Boolean value)

Each put method takes a String key and a typed value as parameters. When using ContentValues to insert data into a database, the key parameter must match the name of the column for the table that is targeted by the insert.

In addition to the overloaded put methods just listed, there is also a put(ContentValues other) method that can be used to add all the values from another ContentValues object, and a putNull(String key) method that adds a null value to a column of a table.

In a typical use case, a new instance of ContentValues is created and populated with all the values that should be inserted into the table. The ContentValues object is then passed to one of the insert methods from SQLiteDatabase. Listing 5.1 shows typical ContentValues usage.

Listing 5.1 Inserting Data with SQLiteDatabase.insert()

The code in Listing 5.1 passes a null for the value of the nullColumnHack to the SQLiteDatabase.insert() method. This is primarily because the code in Listing 5.1 “knows” what values were used to populate the values parameter and can ensure that there is at least one column represented in the ContentValues object. However, this is not always the case, and this is why the nullColumnHack parameter exists.

To explain nullColumnHack, consider the case where a ContentValues object that is inserted into a table contains no key/value pairs. This would amount to attempting to perform an insert operation without specifying any columns to insert data into. Such an insert statement is illegal in SQL because an insert statement must specify at least one column to insert data into. The nullColumnHack parameter can be used to guard against the “empty ContentValues” use case by specifying the name of a column that should be set to null in the case that the ContentValues object contains no data. Like the keys in the ContentValues instance, the string value for nullColumnHack must match the name of a column in the table that is targeted by the insert statement.

Listing 5.2 contains a usage of the nullColumnHack parameter. After the code in Listing 5.2 is run, column last_name will contain a value of null.

Listing 5.2 Specifying Null Columns with nullColumnHack

All three insert methods of SQLiteDatabase return a long. The value returned by the methods is the row ID of the inserted row, or a value of –1 if there was an error performing the insert.

Источник

Оцените статью