• 3
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

One of our app requirements is that some SQLite file should be retained and backup, even the app is uninstalled.

We achieve such, by writing SQLite file via Room, into location Environment.getExternalStorageDirectory

RoomDatabase with customizable SQLite file path

@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;
    }
}

Function returns 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;
}

How we save SQLite file via Room in external storage

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

According to this, my understanding is that Environment.getExternalStorageDirectory might not be usable anymore (am I correct??).

My guess is that, in order to achieve the same behavior, I might need to use MediaStore.Downloads? But how?

Can anyone provide a concrete example for the above use case? Or, we are no longer possible to achieve such behavior, under Scoped storage?

From my own experiments with the Q beta 2 emulator, with a test app with targetSdkVersion 'Q':

Initially Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).exists() was false, which led me to believe you can't even access it in Q. Then I found mkdirs() worked, and I could then read and write to a sandboxed view of this folder restricted to my app's files only. This has the interesting side effect that multiple apps can write files with the same name to the 'download' folder, and that's how they show in the default files app on the emulator!

As the docs mention, you lose access to your own files after uninstall then reinstall. So, in order to restore a sqlite file from downloads after uninstall, you'd have to:

  • "allow the user to choose a file using the system's file picker app." (from docs)
  • This will give you a URI rather than a File. Because SQLiteDatabase can only read Files, you'll need to open the URI as a stream and write it to a real file somewhere you control, eg cache or internal storage.

This is a pain, but doable for most use cases. It gets tricky for very large database files, eg mapbox tiles which may be hundreds of mb or more, stored on an actual SD card because they won't fit on regular 'external' storage.

  • 1
Reply Report
      • 1
    • Thanks for hint. Do you have any idea on how can we (Or is it possible), that we can copy multiple image files to Shared collections Downloads?

As stated here, the files located in your external storage will be removed upon uninstallation of your application. Hence, you might consider using getExternalStoragePublicDirectory function to store your files in the top level shared storage. If you want to store in the DOWNLOADS directory, you can use the following to get the directory path.

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

Hope that helps.

  • 0
Reply Report
      • 1
    • I think I understood your problem. Keeping the files in the MediaStore.Download is the same as you store the file in the DIRECTORY_DOWNLOADS using the getExternalStoragePublicDirectory function in my opinion. Though the blog that you shared does not say much about it. Please let me know if I have got anything wrong again.