Как подключить room android studio
Полный текст статьи и исходники программы доступны только зарегистрированным участникам сайта.
Прочитайте внимательно условия! В начале каждой статьи указывается, к какому курсу относится данная статья. Например, если статья из 4 курса, значит нужно заплатить за все курсы по четвёртый включительно.
Стоимость регистрации — символические 355 рублей. После регистрации у вас будет доступ ко второму курсу.
Для регистрации сначала необходимо пополнить ЮMoney 410011383280263 на указанную сумму или QIWI (перевод по никнейму), а затем прислать письмо на адрес [email protected] с указанием, на какой кошелёк вы делали оплату и реквизиты, по которым можно вас определить (не прикрепляйте к письму картинки или файлы, пишите в письме). Учитывайте комиссию при переводах.
По поводу перевода на ЮMoney. Если делать перевод по указанной ссылке, то к сумме нужно прибавить 3% самостоятельно. Если вы знаете, как переводить по номеру кошелька 410011383280263 без указанной ссылки, то по идее ваш банк сам рассчитает комиссию. Эти новые правила стали применяться в октябре 2022, возможно вам придётся доплачивать, когда я увижу точную сумму прихода.
Не присылайте в письме мои номера кошельков — поверьте, я их знаю и без вас.
В ответном письме вы получите учётные данные для чтения статей из закрытой зоны за второй курс.
Доступ к третьему курсу обучения доступен только после оплаты второго курса и составляет 355 руб.
Доступ к четвёртому курсу обучения доступен после оплаты третьего курса и составляет 355 руб. и т.д.
При оплате сразу всех курсов одновременно (2-10) цена составит 3195 руб.
Доступ даётся как минимум на один год. Для тех, кто оплатил третий и другие курсы, сроки доступа увеличиваются.
Также возможен приём на PayPal (только для зарубежных пользователей). Обратите внимание, что в этом случае стоимость одного курса составляет 7$.
На данный момент PayPal не доступен в России.
Webmoney тоже не особо доступен в России, но по запросу можно отправить на Z-кошелёк (7S), если вдруг кому-то удобно из других стран.
Android, Room «не пишет» в базу данных
Делаю приложение, основной контент которого находится в SQLite базе. Викторина, в которой предлагается угадать животное. Начал изучать Room. Всё работает, информация сохраняется и извлекается из db в рантайме(вижу через логи и Toast). Но когда я открываю саму db(физически) в браузере (DB Browser), то вижу там пустоту. Ни таблиц, ничего. А должны быть мои записи. Что я хочу сделать: открыть только что установленное приложение, добавить в db несколько записей, закрыть приложение, скачать созданную db с устройства на PC и открыть её в браузере, чтобы увидеть её структуру. Пошагово что сделано и где затык: Рутанул эмулятор. Определил путь создаваемой Room базы через: Timber.d(getDatabasePath(AnimalDatabase.DATABASE_NAME).getPath()); Получил: /data/user/0/com.example.animalslibrary/databases/AnimalDB Удалил приложение. Удалил руками вообще весь пакет com.example.animalslibrary . Устанавливаю приложение. Приложение открыто, ни одной записи не добавлено(запись добавляется руками по кнопке). По указанному выше пути ничего не создалось:
Добавляю запись по кнопке. Создаются файлы с моей базой(?) и ещё чем — то непонятным:
Продолжаю добавлять записи кнопкой. Моя база AnimalBD не меняет размера, зато третий файл жиреет с ошеломительной скоростью(скрин после добавления пяти записей):
Закрываю приложение. Скачиваю AnimalBD , открываю — пустота, чистый лист. Даже таблиц нет. Запускаю приложение ещё раз. Пробую достать запись из базы — достаётся. Что я делаю не так вообще? Реально ли достать базу? И если нет, то что мне делать если я хочу чтобы у пользователя уже была заполненная база на момент первого запуска приложения? Не буду же я кодом добавлять уйму строк. В комментариях посоветовали подменять создаваемую Room базу на свою при первом запуске — но для этого мне ведь нужно понять как устроено то что Room создаёт, чтобы создать аналог. Код. Не уверен что он тут вообще нужен, т.к всё работает. Но пусть будет. Не кидайтесь камнями за перегруженную архитектуру, познаю MVC. Activity
HomeModel homeModel = new HomeModel(Room.databaseBuilder(this, AnimalDatabase.class, AnimalDatabase.DATABASE_NAME) .allowMainThreadQueries() .build()); HomePresenter presenter = new HomePresenter(homeModel); presenter.attachView(this); findViewById(R.id.add_animal_button).setOnClickListener(v -> presenter.buttonClicked()); findViewById(R.id.show_animal_button).setOnClickListener(v -> presenter.button1Clicked()); Timber.d(getDatabasePath(AnimalDatabase.DATABASE_NAME).getPath());
HomePresenter
public class HomePresenter < private HomeActivity view; private HomeModel model; public HomePresenter(HomeModel homeModel) < this.model = homeModel; >public void attachView(HomeActivity activity) < this.view = activity; >public void detachView() < this.view = null; >public void viewIsReady() < >public void buttonClicked() < model.addAnimal(); Toast.makeText(view,"ADDED",Toast.LENGTH_LONG).show(); >public void button1Clicked()
HomeModel
public class HomeModel < private AnimalDatabase animalDB; public HomeModel(AnimalDatabase animalDB) < this.animalDB = animalDB; >public void addAnimal() < Animal animal = new Animal(); animal.setName("TIGER"); animalDB.daoAccess().insertAnimal(animal); >public Animal getAnimalById(int id) < return animalDB.daoAccess().getAnimalById(id); >public void initDB()<> >
DAO
@Dao public interface DAO < @Insert void insertAnimal(Animal animal); @Insert void insertAnimals(ListanimalList); @Query("SELECT*FROM animals WHERE animal_id =:animalId") Animal getAnimalById(int animalId); @Update void updateAnimal(Animal animal); @Delete void deleteAnimal(Animal animal);
> AnimalDatabase
@Database(entities = , version = 1) @TypeConverters(Converters.class) public abstract class AnimalDatabase extends RoomDatabase
Animal
@Entity(tableName = "animals") public class Animal implements Serializable < @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "animal_id") private int animalId; @ColumnInfo(name = "animal_type") private int type; @ColumnInfo(name = "animal_name") private String name; @ColumnInfo(name = "animal_hints") private String hints; @ColumnInfo(name = "animal_opened_hints") private int hintsOpened; @ColumnInfo(name = "animal_hints_total") private int hintsTotal; @ColumnInfo(name = "animal_pack_id") private int packId; @ColumnInfo(name = "animal_answer_image") private String answerImagePath; public Animal() < >//Тьма геттеров и сеттеров //+ пустой конструктор //+ конструктор, содержащий все поля >
Урок 5. Room. Основы
Библиотека Room предоставляет нам удобную обертку для работы с базой данных SQLite. В этом уроке рассмотрим основы. Как подключить к проекту. Как получать, вставлять, обновлять и удалять данные.
Полный список уроков курса:
- Урок 1. Lifecycle
- Урок 2. LiveData
- Урок 3. LiveData. Дополнительные возможности
- Урок 4. ViewModel
- Урок 5. Room. Основы
- Урок 6. Room. Entity
- Урок 7. Room. Insert, Update, Delete, Transaction
- Урок 8. Room. Query
- Урок 9. Room. RxJava
- Урок 10. Room. Запрос из нескольких таблиц. Relation
- Урок 11. Room. Type converter
- Урок 12. Room. Миграция версий базы данных
- Урок 13. Room. Тестирование
- Урок 14. Paging Library. Основы
- Урок 15. Paging Library. PagedList и DataSource. Placeholders.
- Урок 16. Paging Library. LivePagedListBuilder. BoundaryCallback.
- Урок 17. Paging Library. Виды DataSource
- Урок 18. Android Data Binding. Основы
- Урок 19. Android Data Binding. Код в layout. Доступ к View
- Урок 20. Android Data Binding. Обработка событий
- Урок 21. Android Data Binding. Observable поля. Двусторонний биндинг.
- Урок 22. Android Data Binding. Adapter. Conversion.
- Урок 23. Android Data Binding. Использование с include, ViewStub и RecyclerView.
- Урок 24. Navigation Architecture Component. Введение
- Урок 25. Navigation. Передача данных. Type-safe аргументы.
- Урок 26. Navigation. Параметры навигации
- Урок 27. Navigation. NavigationUI.
- Урок 28. Navigation. Вложенный граф. Global Action. Deep Link.
- Урок 29. WorkManager. Введение
- Урок 30. WorkManager. Критерии запуска задачи.
- Урок 31. WorkManager. Последовательность выполнения задач.
- Урок 32. WorkManager. Передача и получение данных
- Урок 33. Практика. О чем это будет.
- Урок 34. Практика. TodoApp. Список задач.
- Урок 35. Практика. TodoApp. Просмотр задачи
Подключение к проекту
В build.gradle файл проекта добавьте репозитарий google()
allprojects < repositories < jcenter() google() >. >
В build.gradle файле модуля добавьте dependencies:
dependencies
Если у вас студия ниже 3.0 и старые версии Gradle и Android Plugin, то подключение будет выглядеть так:
buildscript < repositories < jcenter() maven < url 'https://maven.google.com' >> . >
dependencies
Room
Room имеет три основных компонента: Entity, Dao и Database. Рассмотрим их на небольшом примере, в котором будем создавать базу данных для хранения данных по сотрудникам (англ. - employee).
При работе с Room нам необходимо будет писать SQL запросы. Если вы не знакомы с ними, то имеет смысл прочесть хотя бы основы.
Entity
Аннотацией Entity нам необходимо пометить объект, который мы хотим хранить в базе данных. Для этого создаем класс Employee, который будет представлять собой данные сотрудника: id, имя, зарплата:
@Entity public class Employee
Класс помечается аннотацией Entity. Объекты класса Employee будут использоваться при работе с базой данных. Например, мы будем получать их от базы при запросах данных и отправлять их в базу при вставке данных.
Этот же класс Employee будет использован для создания таблицы в базе. В качестве имени таблицы будет использовано имя класса. А поля таблицы будут созданы в соответствии с полями класса.
Аннотацией PrimaryKey мы помечаем поле, которое будет ключом в таблице.
В следующих уроках мы рассмотрим возможности Entity более подробно.
Dao
В объекте Dao мы будем описывать методы для работы с базой данных. Нам нужны будут методы для получения списка сотрудников и для добавления/изменения/удаления сотрудников.
Описываем их в интерфейсе с аннотацией Dao.
@Dao public interface EmployeeDao < @Query("SELECT * FROM employee") ListgetAll(); @Query("SELECT * FROM employee WHERE Employee getById(long id); @Insert void insert(Employee employee); @Update void update(Employee employee); @Delete void delete(Employee employee); >
Методы getAll и getById позволяют получить полный список сотрудников или конкретного сотрудника по id. В аннотации Query нам необходимо прописать соответствующие SQL-запросы, которые будут использованы для получения данных.
Обратите внимание, что в качестве имени таблицы мы используем employee. Напомню, что имя таблицы равно имени Entity класса, т.е. Employee, но в SQLite не важен регистр в именах таблиц, поэтому можем писать employee.
Для вставки/обновления/удаления используются методы insert/update/delete с соответствующими аннотациями. Тут никакие запросы указывать не нужно. Названия методов могут быть любыми. Главное - аннотации.
В следующих уроках мы рассмотрим возможности Dao и его аннотаций более подробно.
Database
Аннотацией Database помечаем основной класс по работе с базой данных. Этот класс должен быть абстрактным и наследовать RoomDatabase.
@Database(entities = , version = 1) public abstract class AppDatabase extends RoomDatabase
В параметрах аннотации Database указываем, какие Entity будут использоваться, и версию базы. Для каждого Entity класса из списка entities будет создана таблица.
В Database классе необходимо описать абстрактные методы для получения Dao объектов, которые вам понадобятся.
Практика
Все необходимые для работы объекты созданы. Давайте посмотрим, как использовать их для работы с базой данных.
Database объект - это стартовая точка. Его создание выглядит так:
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database").build();
Используем Application Context, а также указываем AppDatabase класс и имя файла для базы.
Учитывайте, что при вызове этого кода Room каждый раз будет создавать новый экземпляр AppDatabase. Эти экземпляры очень тяжелые и рекомендуется использовать один экземпляр для всех ваших операций. Поэтому вам необходимо позаботиться о синглтоне для этого объекта. Это можно сделать с помощью Dagger, например.
Если вы не используете Dagger (или другой DI механизм), то можно использовать Application класс для создания и хранения AppDatabase:
public class App extends Application < public static App instance; private AppDatabase database; @Override public void onCreate() < super.onCreate(); instance = this; database = Room.databaseBuilder(this, AppDatabase.class, "database") .build(); >public static App getInstance() < return instance; >public AppDatabase getDatabase() < return database; >>
Не забудьте добавить App класс в манифест
В коде получение базы будет выглядеть так:
AppDatabase db = App.getInstance().getDatabase();
Из Database объекта получаем Dao.
EmployeeDao employeeDao = db.employeeDao();
Теперь мы можем работать с Employee объектами. Но эти операции должны выполняться не в UI потоке. Иначе мы получим Exception.
Добавление нового сотрудника в базу будет выглядеть так:
Employee employee = new Employee(); employee.id = 1; employee.name = "John Smith"; employee.salary = 10000; employeeDao.insert(employee);
Метод getAll вернет нам всех сотрудников в List
List employees = employeeDao.getAll();
Получение сотрудника по id:
Employee employee = employeeDao.getById(1);
Обновление данных по сотруднику.
employee.salary = 20000; employeeDao.update(employee);
Room будет искать в таблице запись по ключевому полю, т.е. по id. Если в объекте employee не заполнено поле id, то по умолчанию в нашем примере оно будет равно нулю и Room просто не найдет такого сотрудника (если, конечно, у вас нет записи с >
employeeDao.delete(employee);
Аналогично обновлению, Room будет искать запись по ключевому полю, т.е. по id
Давайте для примера добавим еще один тип объекта - Car.
Описываем Entity объект
@Entity public class Car
Теперь Dao для работы с Car объектом
@Dao public interface CarDao < @Query("SELECT * FROM car") ListgetAll(); @Insert void insert(Car car); @Delete void delete(Car car); >
Будем считать, что нам надо только читать все записи, добавлять новые и удалять старые.
В Database необходимо добавить Car в список entities и новый метод для получения CarDao
@Database(entities = , version = 1) public abstract class AppDatabase extends RoomDatabase
Т.к. мы добавили новую таблицу, изменилась структура базы данных. И нам необходимо поднять версию базы данных до 2. Но об этом мы подробно поговорим в Уроке 12. А пока можно оставить версию равной 1, удалить старую версию приложения и поставить новую.
UI поток
Повторюсь, операции по работе с базой данных - синхронные, и должны выполняться не в UI потоке.
В случае с Query операциями мы можем сделать их асинхронными используя LiveData или RxJava. Об этом еще поговорим в следующих уроках.
В случае insert/update/delete вы можете обернуть эти методы в асинхронный RxJava. В моем блоге есть статья на эту тему.
Также, вы можете использовать allowMainThreadQueries в билдере создания AppDatabase
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database") .allowMainThreadQueries() .build();
В этом случае вы не будете получать Exception при работе в UI потоке. Но вы должны понимать, что это плохая практика, и может добавить ощутимых тормозов вашему приложению.
Переход на Room
Если вы надумали с SQLite мигрировать на Room, то вот пара полезных ссылок по этой теме:
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
Room: подключение готовой БД

Задача: имеется готовая дб, ее необходимо использовать в приложении. Собственно вопрос как правильно ее впихувать в приложение.
Первое что приходит в голову это скопировать ДБ в каталог "data/data/"+ context.getPackageName() + "/databases/" и дальше уже обращатся к ней. Но просматривая стэковерфлоу я среди вариантов решения подобных задач, этого варианта не встречал, там везде предлогаются для этого использовать сторонние библиотеки.
Собственно вопрос. Какие сложности могут возникнуть в будущем если базу данных просто скопировать из assets?
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Room использование готовой базы
У меня есть готовая база данных, которую хочу добавить в проект, возникает вопрос, как это сделать.
подключение готовой бд к денверу
делал сайт на движке WordPress на хостинге. перекачал всю папку сайта, нужно подключить ее к.
Подключение Unit к готовой программе
ХЕЛП. Нужно подключить модуль к уже готовой проге. Помогите плиз. program Project1; .
Создание готовой программы из готовой базы данных
Добрый день. Есть полностью готовая база данных с таблицами, формами, отчетами. Короче полностью.
69 / 62 / 13
Регистрация: 10.01.2012
Сообщений: 508
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
public class DBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "main.db"; private static final int DATABASE_VERSION = 1; private static final String TAG = DBHelper.class.getSimpleName(); public DBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); Log.d(TAG, "constructor"); } @Override public void onCreate(SQLiteDatabase db) { // Таблица: android_metadata // db.execSQL("DROP TABLE IF EXISTS android_metadata"); db.execSQL("CREATE TABLE IF NOT EXISTS android_metadata (locale TEXT)"); db.execSQL("INSERT INTO android_metadata (locale) VALUES ('ru_RU')"); // Таблица: City db.execSQL("DROP TABLE IF EXISTS City"); db.execSQL("CREATE TABLE City (`num` INTEGER UNIQUE ON CONFLICT REPLACE, `City_id` INTEGER (10), `Country_id` INTEGER (20), `City_ru` VARCHAR (150), `City_en` VARCHAR (150), `City_by` VARCHAR (150), `City_uk` VARCHAR (150), `server` VARCHAR (150), `Port` VARCHAR (10), `Regional_db` VARCHAR (100))"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (1, 0, 0, '0 Укажите город', '0 Add City', '0 Укажыце горад', '0 Вкажіть місто', '0', '0', '0')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (2, 83147, 7, 'Арзамас', 'Arzamas', 'Арзамас', 'Арзамас', '172.14.2.100', '8084', 'main_arzamas.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (3, 81738, 7, 'В.Устюг', 'V.Ustyug', 'В.Устюг', 'В.Устюг', '172.14.2.100', '8084', 'main_ustyug.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (4, 48532, 7, 'Углич', 'Uglich', 'Угліч', 'Углич', '172.14.2.100', '8084', 'main_uglich.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (5, 8202, 7, 'Череповец', 'Cherepovets', 'Чарапавец', 'Череповець', '172.14.2.100', '8084', 'main_cherepovetc.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (6, 4143, 380, 'Бердичев', 'Berdichev', 'Бердичев', 'Бердичів', '172.14.2.100', '8084', 'main_berdichev.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (7, 4574, 380, 'Мироновка', 'Mironovka', 'Мироновка', 'Миронівка', '172.14.2.100', '8084', 'main_mironovka.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (8, 3133, 380, 'Свалява', 'Svaliava', 'Свалява', 'Свалява', '172.14.2.100', '8084', 'main_svaliava.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (9, 34940, 7, 'ПГТ Тазовский', 'Tazovsky', 'ПГТ Тазовской', 'СМТ Тазовский', '172.14.2.100', '8084', 'main_tazovsky.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (10, 412, 380, 'Житомир', 'Zhitomir', 'Жытомір', 'Житомир', '172.14.2.100', '8084', 'main_zhitomir.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (11, 3122, 380, 'Ужгород', 'Uzhgorod', 'Ужгород', 'Ужгород', '172.14.2.100', '8084', 'main_uzhgorod.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (12, 34145, 7, 'Воткинск', 'Votkinsk', 'Воткінск', 'Воткинськ', '172.14.2.100', '8084', 'main_votkinsk.drivers_db')"); db.execSQL("INSERT INTO City (num, City_id, Country_id, City_ru, City_en, City_by, City_uk, server, Port, Regional_db) VALUES (13, 225, 375, 'Бобруйск', 'Bobruisk', 'Бабруйск', 'Бобруйськ', '172.14.2.100', '8084', 'main_bobruisk.drivers_db')"); // Таблица: DriversDbClass // db.execSQL("DROP TABLE IF EXISTS DriversDbClass"); db.execSQL("CREATE TABLE IF NOT EXISTS DriversDbClass (num INTEGER PRIMARY KEY AUTOINCREMENT, Country_id INTEGER (10), Country_ru STRING (100), Country_en STRING (100), Country_uk STRING (100), Country_by STRING (100))"); db.execSQL("INSERT INTO DriversDbClass (num, Country_id, Country_ru, Country_en, Country_uk, Country_by) VALUES (1, 0, '0 Укажите страну', '0 Add DriversDbClass', '0 Вкажіть країну', '0 Укажыце краіну')"); db.execSQL("INSERT INTO DriversDbClass (num, Country_id, Country_ru, Country_en, Country_uk, Country_by) VALUES (2, 375, 'Беларусь', 'Belarus', 'Білорусь', 'Беларусь')"); db.execSQL("INSERT INTO DriversDbClass (num, Country_id, Country_ru, Country_en, Country_uk, Country_by) VALUES (3, 7, 'Россия', 'Russia', 'Росія', 'Расія')"); db.execSQL("INSERT INTO DriversDbClass (num, Country_id, Country_ru, Country_en, Country_uk, Country_by) VALUES (4, 380, 'Украина', 'Ukraine', 'Україна', 'Украіна')"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Update database from version " + oldVersion + " to " + newVersion + ", which remove all old records"); onCreate(db); } }
Регистрация: 11.08.2016
Сообщений: 87
zoleg, Нет, там довольно большая дб. Оно то можно и подобным образом скопировать. Но меня интересуюют именно негативные последствия моего подхода которые могут выплысть в будущем.
69 / 62 / 13
Регистрация: 10.01.2012
Сообщений: 508

Сообщение было отмечено Gukamanav как решение
Решение
Сообщение от Gukamanav 
Собственно вопрос. Какие сложности могут возникнуть в будущем если базу данных просто скопировать из assets?
НИкаких. Если очень страшно, то, при установке проги, копируйте БД из assets в data/data/ как файл или дампом, - в общем куча вариантов.