page.title=Сохранение данных в базах данных SQL page.tags=хранение данных helpoutsWidget=true trainingnavtop=true @jd:body
Сохранение данных в базе идеально подходит для повторяющихся и структурированных данных, таких как контактная информация. В этом учебном курсе предполагается, что вы владеете общими знаниями о базах данных SQL, и он поможет вам начать работать с базами данных SQLite на платформе Android. API-интерфейсы, необходимые для использования базы данных на платформе Android, доступны в составе пакета {@link android.database.sqlite}.
Одним из основных элементов баз данных SQL является схема, которая представляет собой формальную декларацию способа организации базы данных. Схема отражается в выражениях SQL, используемых для создания базы данных. Для вас может оказаться полезным создать сопутствующий класс (класс-контракт), явно указывающий структуру схемы систематическим и самодокументирующим способом.
Класс-контракт представляет собой контейнер, определяющий имена для URI-адресов, таблиц и столбцов. Класс-контракт позволяет использовать одни и те же постоянные значения во всех других классах этого же пакета. Таким образом, при изменении имени столбца в одном месте это изменение применяется во всем коде.
Для удобства организации класс-контракта стоит поместить глобальные определения базы данных на корневой уровень класса. Затем нужно создать внутренний класс для каждой таблицы, производящей нумерацию столбцов.
Примечание. За счет реализации интерфейса {@link android.provider.BaseColumns} внутренний класс может наследовать поле первичного ключа {@code _ID}, наличия которого ожидают от него некоторые классы Android (например, адаптеры курсора). Это не является обязательным условием, однако может помочь обеспечить гармоничную работу вашей базы данных в инфраструктуре Android.
Например, в этом фрагменте кода определяются имя таблицы и имена столбцов для одной таблицы:
public final class FeedReaderContract { // To prevent someone from accidentally instantiating the contract class, // give it an empty constructor. public FeedReaderContract() {} /* Inner class that defines the table contents */ public static abstract class FeedEntry implements BaseColumns { public static final String TABLE_NAME = "entry"; public static final String COLUMN_NAME_ENTRY_ID = "entryid"; public static final String COLUMN_NAME_TITLE = "title"; public static final String COLUMN_NAME_SUBTITLE = "subtitle"; ... } }
После определения внешнего вида базы данных следует реализовать методы создания и обслуживания базы данных и таблиц. Вот некоторые типичные выражения для создания и удаления таблиц:
private static final String TEXT_TYPE = " TEXT"; private static final String COMMA_SEP = ","; private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" + FeedEntry._ID + " INTEGER PRIMARY KEY," + FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP + FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP + ... // Any other options for the CREATE command " )"; private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
Как и при сохранении файлов во внутренней памяти устройства, Android сохраняет вашу базу данных в закрытой области диска, связанной с приложением Эти данные защищены, потому что эта область по умолчанию недоступна другим приложениям.
Полезный набор API-интерфейсов содержится в классе {@link android.database.sqlite.SQLiteOpenHelper}. Если вы используете этот класс для получения ссылок на свою базу данных, система выполняет потенциально долговременные операции создания и обновления базы данных только тогда, когда это необходимо, а не при запуске приложения. Для этого нужно использовать вызов {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} или {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}.
Примечание. Поскольку операции могут выполняться длительное время, вызывайте {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} или {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} в фоновом потоке, например с {@link android.os.AsyncTask} или {@link android.app.IntentService}.
Для использования {@link android.database.sqlite.SQLiteOpenHelper} создайте подкласс, заменяющий методы вызова {@link android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()}, {@link android.database.sqlite.SQLiteOpenHelper#onUpgrade onUpgrade()} и {@link android.database.sqlite.SQLiteOpenHelper#onOpen onOpen()}. Также вы можете использовать {@link android.database.sqlite.SQLiteOpenHelper#onDowngrade onDowngrade()}, но это не требуется.
Например, вот реализация {@link android.database.sqlite.SQLiteOpenHelper}, при которой используются некоторые из приведенных выше команд:
public class FeedReaderDbHelper extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "FeedReader.db"; public FeedReaderDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // This database is only a cache for online data, so its upgrade policy is // to simply to discard the data and start over db.execSQL(SQL_DELETE_ENTRIES); onCreate(db); } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } }
Для получения доступа к базе данных создайте экземпляр подкласса {@link android.database.sqlite.SQLiteOpenHelper}:
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
Добавьте данные в базу данных, передав объект {@link android.content.ContentValues} в метод {@link android.database.sqlite.SQLiteDatabase#insert insert()}:
// Gets the data repository in write mode SQLiteDatabase db = mDbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id); values.put(FeedEntry.COLUMN_NAME_TITLE, title); values.put(FeedEntry.COLUMN_NAME_CONTENT, content); // Insert the new row, returning the primary key value of the new row long newRowId; newRowId = db.insert( FeedEntry.TABLE_NAME, FeedEntry.COLUMN_NAME_NULLABLE, values);
Первый аргумент {@link android.database.sqlite.SQLiteDatabase#insert insert()} представляет собой просто название таблицы. Второй аргумент указывает имя столбца, в который инфраструктура вставляет значение NULL, если {@link android.content.ContentValues} является пустым (если вместо этого указать {@code "null"}, то инфраструктура не будет вставлять строку в случае отсутствия значений).
Для чтения из базы данных используйте метод {@link android.database.sqlite.SQLiteDatabase#query query()} с передачей критериев выделения и желаемых столбцов. Метод сочетает элементы {@link android.database.sqlite.SQLiteDatabase#insert insert()} и {@link android.database.sqlite.SQLiteDatabase#update update()}, за исключением того, что список столбцов определяет данные, которые вы хотите получить, а не данные для вставки. Результаты запроса возвращаются в объекте {@link android.database.Cursor}.
SQLiteDatabase db = mDbHelper.getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { FeedEntry._ID, FeedEntry.COLUMN_NAME_TITLE, FeedEntry.COLUMN_NAME_UPDATED, ... }; // How you want the results sorted in the resulting Cursor String sortOrder = FeedEntry.COLUMN_NAME_UPDATED + " DESC"; Cursor c = db.query( FeedEntry.TABLE_NAME, // The table to query projection, // The columns to return selection, // The columns for the WHERE clause selectionArgs, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order );
Чтобы посмотреть на строку в месте курсора, используйте один из методов перемещения {@link android.database.Cursor}, которые всегда нужно вызывать перед считыванием значений. Обычно следует начинать с вызова {@link android.database.Cursor#moveToFirst}, который помещает "позицию чтения" на первую запись в результатах. Для каждой строки значение столбца можно прочитать, вызвав один из методов {@link android.database.Cursor} get, например {@link android.database.Cursor#getString getString()} или {@link android.database.Cursor#getLong getLong()}. Для каждого из методов get вы должны передать указатель желаемого столбца, который может вызвать {@link android.database.Cursor#getColumnIndex getColumnIndex()} или {@link android.database.Cursor#getColumnIndexOrThrow getColumnIndexOrThrow()}. Например:
cursor.moveToFirst(); long itemId = cursor.getLong( cursor.getColumnIndexOrThrow(FeedEntry._ID) );
Для удаления строк из таблицы нужно указать критерии выделения, идентифицирующие строки. API-интерфейс базы данных обеспечивает механизм для создания критериев выделения, предоставляющий защиту от внедрения SQL-кода. Механизм делит спецификацию выбора на предложение выбора и аргументы выбора. Предложение определяет столбцы для рассмотрения, а также позволяет объединять операции тестирования столбцов. Аргументы представляют собой значения для тестирования, которые привязаны к пункту. Поскольку результат обрабатывается не как обычные выражения SQL, он защищен от внедрения SQL-кода.
// Define 'where' part of query. String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; // Specify arguments in placeholder order. String[] selectionArgs = { String.valueOf(rowId) }; // Issue SQL statement. db.delete(table_name, selection, selectionArgs);
При необходимости изменить набор значений базы данных используйте метод {@link android.database.sqlite.SQLiteDatabase#update update()}.
Обновление таблицы сочетает значения синтаксиса {@link android.database.sqlite.SQLiteDatabase#insert insert()} и синтаксиса {@code where} для {@link android.database.sqlite.SQLiteDatabase#delete delete()}.
SQLiteDatabase db = mDbHelper.getReadableDatabase(); // New value for one column ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_TITLE, title); // Which row to update, based on the ID String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; String[] selectionArgs = { String.valueOf(rowId) }; int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME, values, selection, selectionArgs);