Я реализовал BackupAgentHelper
использование предоставленного FileBackupHelper
для резервного копирования и восстановления собственной базы данных, которая у меня есть. Это база данных, с которой вы обычно работаете ContentProviders
и которая находится в ней /data/data/yourpackage/databases/
.
Казалось бы, это обычный случай. Однако в документах неясно, что делать: http://developer.android.com/guide/topics/data/backup.html . Там нет BackupHelper
специально для этих типичных баз данных. Следовательно, я использовалFileBackupHelper
, указал его на свой .db файл в " /databases/
", ввел блокировки вокруг любой операции с базой данных (например, db.insert
) в моем ContentProviders
, и даже попытался создать /databases/
каталог " " раньше, onRestore()
потому что он не существует после установки.
В прошлом я успешно реализовал подобное решение для SharedPreferences
другого приложения. Однако, когда я тестирую свою новую реализацию в эмуляторе 2.2, я вижу, что выполняется резервное копирование LocalTransport
из журналов, а также выполняется (и onRestore()
вызывается) восстановление . Однако сам файл db никогда не создается.
Обратите внимание, что это все после установки и перед первым запуском приложения, после того как было выполнено восстановление. Кроме того, моя стратегия тестирования была основана на http://developer.android.com/guide/topics/data/backup.html#Testing .
Также обратите внимание, что я не говорю ни о какой-то базе данных sqlite, которой я управляю сам, ни о резервном копировании на SD-карту, собственный сервер или где-то еще.
Я действительно видел упоминание в документации о базах данных, рекомендующих использовать обычай, BackupAgent
но это не похоже на связь:
Однако вы можете напрямую расширить BackupAgent, если вам нужно: * Резервное копирование данных в базе данных. Если у вас есть база данных SQLite, которую вы хотите восстановить, когда пользователь переустанавливает ваше приложение, вам необходимо создать настраиваемый агент BackupAgent, который считывает соответствующие данные во время операции резервного копирования, затем создает вашу таблицу и вставляет данные во время операции восстановления.
Некоторая ясность, пожалуйста.
Если мне действительно нужно сделать это самому до уровня SQL, то меня беспокоят следующие темы:
Открытые базы данных и транзакции. Я понятия не имею, как закрыть их из такого одноэлементного класса вне рабочего процесса моего приложения.
Как уведомить пользователя о том, что выполняется резервное копирование и база данных заблокирована. Это может занять много времени, поэтому мне может потребоваться показать индикатор выполнения.
Как сделать то же самое при восстановлении. Насколько я понимаю, восстановление может произойти только тогда, когда пользователь уже начал использовать приложение (и вводить данные в базу данных). Таким образом, вы не можете себе позволить просто восстановить данные из резервной копии на месте (удалив пустые или старые данные). Вам придется как-то присоединиться к нему, что для любой нетривиальной базы данных невозможно из-за идентификатора.
Как обновить приложение после завершения восстановления, чтобы пользователь не застрял в какой-то - сейчас - недоступной точке.
Могу ли я быть уверен, что база данных уже была обновлена при резервном копировании или восстановлении? В противном случае ожидаемая схема может не совпадать.
Ответы:
Более чистый подход - создать собственный
BackupHelper
:public class DbBackupHelper extends FileBackupHelper { public DbBackupHelper(Context ctx, String dbName) { super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath()); } }
а затем добавьте его в
BackupAgentHelper
:public void onCreate() { addHelper(DATABASE, new DbBackupHelper(this, DB.FILE)); }
источник
Вернувшись к своему вопросу, я смог заставить его работать, посмотрев, как это делает ConnectBot . Спасибо Кенни и Джеффри!
На самом деле это так же просто, как добавить:
FileBackupHelper hosts = new FileBackupHelper(this, "../databases/" + HostDatabase.DB_NAME); addHelper(HostDatabase.DB_NAME, hosts);
к вашему
BackupAgentHelper
.Мне не хватало того факта, что вам придется использовать относительный путь с "
../databases/
".Тем не менее, это отнюдь не идеальное решение. Документы для
FileBackupHelper
упоминания, например: «FileBackupHelper
следует использовать только с небольшими файлами конфигурации, а не с большими двоичными файлами. », Последнее относится к базам данных SQLite.Я хотел бы получить больше предложений, понимание того, что от нас ожидается (какое решение является правильным), и советы о том, как это может сломаться.
источник
db.open()
черезdb.close()
или простоinsert
заявление или что.Вот еще более удобный способ резервного копирования баз данных в виде файлов. Нет жестко заданных путей.
class MyBackupAgent extends BackupAgentHelper{ private static final String DB_NAME = "my_db"; @Override public void onCreate(){ FileBackupHelper dbs = new FileBackupHelper(this, DB_NAME); addHelper("dbs", dbs); } @Override public File getFilesDir(){ File path = getDatabasePath(DB_NAME); return path.getParentFile(); } }
Примечание: он переопределяет getFilesDir, поэтому FileBackupHelper работает в каталоге баз данных, а не в каталоге файлов.
Еще один совет: вы также можете использовать databaseList, чтобы получить все имена ваших БД и каналов из этого списка (без родительского пути) в FileBackupHelper. Тогда все БД приложения будут сохранены в резервной копии.
источник
Использование
FileBackupHelper
sqlite db для резервного копирования / восстановления вызывает ряд серьезных вопросов:1. Что произойдет, если приложение использует полученный курсор,
ContentProvider.query()
а агент резервного копирования попытается переопределить весь файл?2. Ссылка - хороший пример идеального (с низкой энтрофией;) тестирования. Вы удаляете приложение, устанавливаете его снова, и резервная копия восстанавливается. Однако жизнь может быть жестокой. Взгляните на ссылку . Представим себе сценарий, когда пользователь покупает новое устройство. Поскольку у него нет собственного набора, агент резервного копирования использует набор другого устройства. Приложение установлено, и ваш backupHelper извлекает старый файл со схемой версии базы данных ниже текущей.
SQLiteOpenHelper
вызовыonDowngrade
с реализацией по умолчанию:public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { throw new SQLiteException("Can't downgrade database from version " + oldVersion + " to " + newVersion); }
Независимо от того, что делает пользователь, он не может использовать ваше приложение на новом устройстве.
Я бы предложил использовать
ContentResolver
для получения данных -> сериализовать (без_id
s) для резервного копирования и десериализовать -> вставить данные для восстановления.Примечание: получение / вставка данных выполняется через ContentResolver, что позволяет избежать проблем с валютой. Сериализация выполняется в вашем агенте резервного копирования. Если вы выполняете собственное отображение объекта cursor <->, сериализацию элемента можно так же просто, как реализовать его
Serializable
с помощьюtransient
поля _id в классе, представляющем вашу сущность.Я бы также использовать большую вставку , т.е. ,
ContentProviderOperation
например , иCursorLoader.setUpdateThrottle
так , что приложение не застрял с перезапуском погрузчиком на изменение данных во время резервного копирования процесс восстановления.Если вы оказались в ситуации перехода на более раннюю версию, вы можете либо отменить восстановление данных, либо восстановить и обновить ContentResolver с полями, относящимися к пониженной версии.
Я согласен с тем, что эта тема непростая, недостаточно хорошо объяснена в документации, и некоторые вопросы по-прежнему остаются такими, как размер массива данных и т. Д.
Надеюсь это поможет.
источник
Начиная с Android M, теперь для приложений доступен API резервного копирования / восстановления полных данных. Этот новый API включает в себя спецификацию на основе XML в манифесте приложения, которая позволяет разработчику описывать файлы для резервного копирования прямым семантическим способом: «резервное копирование базы данных под названием« mydata.db »». Этот новый API намного проще использовать разработчикам - вам не нужно отслеживать различия или явно запрашивать передачу резервного копирования, а XML-описание файлов для резервного копирования означает, что вам часто не нужно писать какой-либо код. совсем.
(Вы можете принять участие даже в операции резервного копирования / восстановления полных данных, чтобы, например, получить обратный вызов, когда происходит восстановление. Это гибкий способ.)
См. Раздел « Настройка автоматического резервного копирования для приложений » на сайте developer.android.com, где описано, как использовать новый API.
источник
Один из вариантов - встроить его в логику приложения над базой данных. Думаю, он действительно кричит о таком уровне. Не уверен, что вы это уже делаете, но большинство людей (несмотря на подход курсора к диспетчеру контента Android) представят некоторое сопоставление ORM - либо индивидуальный, либо некоторый подход orm-lite. И в этом случае я бы предпочел:
Поэтому в этом случае, а не на уровне базы данных, сделайте это на уровне приложения.
источник