30
Database Android Дмитрий Колесников

Database (Lecture 14 – database)

  • Upload
    noveo

  • View
    85

  • Download
    6

Embed Size (px)

Citation preview

Page 1: Database (Lecture 14 – database)

DatabaseAndroid

Дмитрий Колесников

Page 2: Database (Lecture 14 – database)

SQLite

встраиваемая реляционная база данныхоткрытый исходный код.нет отдельного серверавысокая скоростьнебольшой расход памятиподдержка стандартных возможностей реляционных БД – синтаксис SQL, транзакции иprepared statementsвся база данных в одном файлекроссплатформенная

http://sqlite.org

Page 3: Database (Lecture 14 – database)

SQLite в Android

доступно на любом устройстве Androidне требует установки БД или администрированиявся работа с базой данных должна быть в отдельном потокефайл БД хранится в каталоге приложения

Page 4: Database (Lecture 14 – database)

SQLite в Android

Contract classSQL HelperSQLiteDatabaseCursorCursorAdapterCursorLoader

Page 5: Database (Lecture 14 – database)

Contract class

Хранит константы, определяющие имена для ваших URI, таблиц, колонок.

Best practice:

создаем класс, который будет хранить константы для всей базы данныхсоздаем внутренние классы с константами для каждой таблицыреализуем интерфейс BaseColumns

Page 6: Database (Lecture 14 – database)

SQLiteOpenHelper

Абстрактный класс, с помощью которого можно создавать, открывать и обновлять базуданных

Создаем наследника и переопределяем следующие методы:onCreate() - вызывается при первом создании базы данныхonUpgrade() - вызывается при модификации базы данных

Должен быть singletonПоле id в таблице должно именоваться _id (На самом деле, нет)close() - закрыть базу.getReadableDatabase()/getWritableDatabase() - создают и/или открывают БД. Возвращаютобъект SQLiteDatabase

Page 7: Database (Lecture 14 – database)

SQLiteDatabase

Работает с базой данных SQLite напрямую, содержит методы:insert()update()- Используют ContentValuesdelete()query() - делает запрос к таблице и возвращает CursorrawQuery() - исполняет sql запрос и возвращает CursorexecSQL() - выполнение одного sql запроса. (NOT a SELECT/INSERT/UPDATE/DELETE)

Page 8: Database (Lecture 14 – database)

Cursor

Возвращается на запрос к базе данных, и предоставляет доступ к результатам запроса. Содержит методы:

moveToFirst()moveToNext()типизированные методы getInt(); getLong();getString(); etcgetColumnIndex()close()

Page 9: Database (Lecture 14 – database)

CursorAdapter

Адаптер, который отображает данные из курсора на ListView

Курсор должен включать столбец с названием "_id" или этот класс не будет работать

Page 10: Database (Lecture 14 – database)

CursorLoader

Позволяет выполнять запросы в отдельном потоке

Наследник AsyncTaskLoader’аLoaders API

Page 11: Database (Lecture 14 – database)

Content Provider

Класс для обмена данными между приложениями.

1 <provider 2 android:authorities="com.noveo.internship.db.exampleContentProvider" 3 android:name=".database.ExampleContentProvider" 4 android:multiprocess="true" 5 android:exported="false" />

Page 12: Database (Lecture 14 – database)

Content Provider

Создаем наследника и переопределяем методы:

onCreate()query()getType()insert()update()delete()

Page 13: Database (Lecture 14 – database)

Content Provider

При работе с провайдером используются URI.

1 content://<authority>/<path>/<id>

authority - уникальное имя ContentProvider-аpath - какие данные нужны (имя таблицы)id - идентификатор записи.

content://com.noveo.db.provider/toys/5 content://com.noveo.db.provider/toys

Page 14: Database (Lecture 14 – database)

UriMatcher

служит для определения деталей запроса к контент- провайдеруотображает URI разных видов на целочисленные константыполезен в случаях, когда обслуживаются разные URI для доступа к одному и тому жеисточнику данных

Пример:

Если URI оканчивается на /toys - это запрос про все игрушкиЕсли на toys/[ID] - про конкретную игрушку

Page 15: Database (Lecture 14 – database)

Жизнь одного запроса1. вызываем getContentResolver().query(Uri, String, String, String, String)2. СontentResolver анализирует Uri и извлекает от туда authority3. ContentResolver направляет запрос к ContentProvider-у зарегестрированному по этому

authority (уникальному)4. ContentProvider выполняет запрос и возвращает Cursor (или исключение)

Page 16: Database (Lecture 14 – database)

Sql to No-Sql

Когда нет желания создавать под каждую сущность отдельную таблицу.

Делаем универсальную таблицу с:idobject_nameobject_versionobject_data

Сравниваем object_version класса object_name с object_version в БД.Достаем object_data и парсим\кастуем к object_name типу.

Page 17: Database (Lecture 14 – database)

ORM

(object-relational mapping)

технология, связывающая таблицы в базе данных с объектами в приложенидля решения данной задачи в Android можно использовать ORMLite

Page 18: Database (Lecture 14 – database)

ORMLite

открытый исходный кодподдержка SQLiteпростые аннотации, быстрый стартпри этом все гибко настраивается, нужно только залезть в документацию http://ormlite.com/http://habrahabr.ru/post/143431/

Page 19: Database (Lecture 14 – database)

ORMLite. Модели

1 @DatabaseTable(tableName = "accounts") 2 public class Account { 3 4 public static final String NAME_FIELD_NAME = "name"; 5 public static final String PASSWORD_FIELD_NAME = "passwd"; 6 7 @DatabaseField(generatedId = true) 8 private int id; 9 @DatabaseField(columnName = NAME_FIELD_NAME, canBeNull = false) 10 private String name; 11 @DatabaseField(columnName = PASSWORD_FIELD_NAME) 12 private String password; 13 @ForeignCollectionField 14 private ForeignCollection<Order> orders; 15 16 Account() { 17 // Пустой конструктор обязательно должен быть(если есть непустые) 18 } 19 // Другие конструкторы 20 // Геттеры, сеттеры и проч. 21 }

Page 20: Database (Lecture 14 – database)

ORMLite. DAO (Data Access Object)

Для каждого класса модели создается DAO (Класс наследник от BaseDaoImpl)

1 public class AccountDAO extends BaseDaoImpl<Account, Integer>{ 2 3 protected AccountDAO(ConnectionSource connectionSource, 4 Class<Account> dataClass) throws SQLException{ 5 super(connectionSource, dataClass); 6 } 7 8 public List<Account> getAllAccounts() throws SQLException{ 9 return this.queryForAll(); 10 } 11 }

Page 21: Database (Lecture 14 – database)

ORMLite. DatabaseHelper

Наследуется от OrmLiteSqliteOpenHelperРеализует методы: onCreate(), onUpgrade()Создает DAO для классов, содержит методы для получения этих DAOДолжен быть синглтоном

Page 22: Database (Lecture 14 – database)

ORMLite. Работа с данными

1 AccountDAO accountDao = DatabaseHelper.getHelper().getAccountDao(); 2 List<Account> accounts = accountDao.getAllAccounts(); 3 for (Account account : accounts) { 4 account.setPassword("new_password"); 5 accountDao.update(account); 6 }

Page 23: Database (Lecture 14 – database)

Realm

Использует собственное хранилище объектов, а не SQLiteРазрабатывалась специально под мобильные платформыНе работает на Java вне Android'аВ операциях чтения показывает производительность выше, чем raw SQLite (в операцияхзаписи ниже)

Page 24: Database (Lecture 14 – database)

Realm. Модели

Модели должны наследоваться от RealmObject

1 public class Person extends RealmObject { 2 3 // По-умолчанию все поля сохраняются в хранилище 4 private String name; 5 private int age; 6 7 // ... Геттеры-сеттеры и т.д. 8 }

Page 25: Database (Lecture 14 – database)

Realm. Транзакции 1 RealmConfiguration realmCfg = new RealmConfiguration.Builder(context).build(); 2 Realm realm = Realm.getInstance(realmCfg); 3 4 final Person person = realm.where(Person.class).findFirst(); 5 6 realm.executeTransaction(new Realm.Transaction() { 7 @Override 8 public void execute(Realm realm) { 9 person.setName("Senior Person"); 10 person.setAge(99); 11 } 12 });

Page 26: Database (Lecture 14 – database)

Realm. Асинхронное выполнение операций 1 RealAsyncTask transaction = realm.executeTransactionAsync(new Realm.Transaction() { 2 @Override 3 public void execute(Realm bgRealm) { 4 //do something 5 } 6 }, new Realm.Transaction.OnSuccess() { 7 @Override 8 public void onSuccess() { 9 // Transaction was a success. 10 } 11 }, new Realm.Transaction.OnError() { 12 @Override 13 public void onError(Throwable error) { 14 // Transaction failed and was automatically canceled. 15 } 16 });

Page 27: Database (Lecture 14 – database)

Realm. Асинхронное выполнение операций

Асинхронные транзакции нужно отменять, если они больше не нужны.

1 public void onStop () { 2 if (transaction != null && !transaction.isCancelled()) { 3 transaction.cancel(); 4 } 5 }

Page 28: Database (Lecture 14 – database)

Realm. Ограничения и недостатки

Вложенные транзакции не поддерживаютсяИмя модели должно быть не больше 57 символов, имя поля - 63 символовString и byte[] должны быть не больше 16МбRealmObject’ы не могут быть ключом в HashMap и храниться в HashSetЕсть некоторые проблемы с сортировкой и поиском по non-Latin строкам

Page 29: Database (Lecture 14 – database)

Debug1. Через adb shell.

cd /data/data/cd com.noveo.internship.dbcd databasesнаходим файл нашей БД, test.db, например, и цепляемся туда.sqlite3 test.db

Нужен рут. Что делать без рута?

Page 30: Database (Lecture 14 – database)

Debug

Сторонние решения. Например Stetho от FB. Позволяет многие вещи, в том числе и инспекцию БД.

SQLite databases can be visualized and interactively explored with full read/writecapabilities.

Stetho