Как записать файл SQLite через Room во внешнее хранилище, используя предстоящее хранилище Scoped? - PullRequest
2 голосов
/ 26 апреля 2019

Одним из требований нашего приложения является сохранение и резервное копирование некоторого файла SQLite, даже если приложение удалено.

Мы достигаем этого, записывая файл SQLite через Room в местоположение Environment.getExternalStorageDirectory

RoomDatabase с настраиваемым путем к файлу SQLite

@Database(
    entities = {Backup.class},
    version = 1
)
public abstract class LocalBackupNamedRoomDatabase extends RoomDatabase {
    public abstract BackupDao backupDao();

    public static LocalBackupNamedRoomDatabase newInstance(String dbName) {
        LocalBackupNamedRoomDatabase INSTANCE = Room.databaseBuilder(
                WeNoteApplication.instance(),
                LocalBackupNamedRoomDatabase.class,
                dbName
        )
                .build();

        return INSTANCE;
    }
}

Функция возвращает Environment.getExternalStorageDirectory

public static String getBackupDirectory() {
    if (backupDirectory == null) {
        File _externalStorageDirectory = Environment.getExternalStorageDirectory();
        if (_externalStorageDirectory == null) {
            return null;
        }

        try {
            backupDirectory = _externalStorageDirectory.getCanonicalPath();
        } catch (IOException e) {
            Log.e(TAG, "", e);
        }

        if (backupDirectory == null) {
            return null;
        }

        backupDirectory = toEndWithFileSeperator(backupDirectory) + "com.yocto.wenote" + File.separator + "backup" + File.separator;
    }

    return backupDirectory;
}

Как сохранить файл SQLite через Room во внешнем хранилище

LocalBackupNamedRoomDatabase.newInstance(
    getBackupDirectory() + "local-backup"
).backupDao().insert(backup)

Согласно этому , я понимаю, что Environment.getExternalStorageDirectory может больше не использоваться (я прав?).

Я предполагаю, что для достижения того же поведения мне может понадобиться MediaStore.Downloads? Но как?

Может ли кто-нибудь привести конкретный пример для приведенного выше варианта использования? Или мы больше не можем добиться такого поведения в хранилище Scoped?

Ответы [ 2 ]

1 голос
/ 28 апреля 2019

Из моих собственных экспериментов с эмулятором Q beta 2, с тестовым приложением с targetSdkVersion 'Q':

Первоначально Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).exists() был ложным, что привело меня к мысли, что вы даже не можете получить к нему доступ в Q. Затем я обнаружил, что mkdirs() работает, и я мог затем читать и записывать в изолированную папку этой папки, ограниченную моим только файлы приложения. Это имеет интересный побочный эффект: несколько приложений могут записывать файлы с одинаковыми именами в папку «download», и именно так они отображаются в приложении файлов по умолчанию на эмуляторе!

Как уже упоминалось в документации, после деинсталляции вы теряете доступ к своим файлам, а затем переустанавливаете. Таким образом, чтобы восстановить файл sqlite из загрузок после удаления, вам необходимо:

  • "разрешить пользователю выбирать файл с помощью системного приложения выбора файлов." (из документов)
  • Это даст вам URI, а не файл. Поскольку SQLiteDatabase может читать только File s, вам нужно открыть URI в виде потока и записать его в реальный файл, который находится под вашим контролем, например, в кэш-памяти или во внутреннем хранилище.

Это боль, но выполнимо для большинства случаев использования. Это очень сложно для очень больших файлов базы данных, например, фрагментов картографии, которые могут быть сотнями мегабайт или больше, хранящихся на реальной SD-карте, потому что они не помещаются в обычное «внешнее» хранилище.

0 голосов
/ 26 апреля 2019

Как указано здесь , файлы, расположенные в вашем внешнем хранилище, будут удалены при удалении вашего приложения. Следовательно, вы можете рассмотреть возможность использования функции getExternalStoragePublicDirectory для хранения ваших файлов в общем хранилище верхнего уровня. Если вы хотите сохранить в каталоге DOWNLOADS , вы можете использовать следующее для получения пути к каталогу.

File path = Environment.getExternalStoragePublicDirectory(
        Environment. DIRECTORY_DOWNLOADS);

Надеюсь, это поможет.

...