Gajanand Swamy
Gajanand Swamy

Reputation: 2108

How to change the default database file location of Room DataBase?

I am using RoomDB in my app. able to perform crud operations. Actually i want to see the db file.

getDatabasePath("user.db").getAbsolutePath();

above code is giving me the directory where the db file is saves directory is like this

 /data/data/com.example.manvish.roomdb/databases/user.db

but still i am unable to access the data directory even using sudo from command prompt. now i want to change the DB file location to some other folders in internal memory or SD card. how can i do this?

Upvotes: 6

Views: 11255

Answers (4)

pjaaar
pjaaar

Reputation: 71

So guys I'm posting my solution because I got stuck for several hours on this problem and I was almost convinced that we couldn't use a database that is located elsewhere than the "/data/data" internal directory of the application with Room

The solution is however very simple. with the following code we have the IllegalArgumentException exception: "File ... contains a path separator"

private fun buildDatabase(context: Context) : RMSRoomDatabase {

        val packageName: String = context.getApplicationInfo().packageName
        var path = "sdcard/Android/data/$packageName/files/rms_database.sqlite"

        var builder = Room.databaseBuilder(
            context,
            RMSRoomDatabase::class.java,
            path
        )

        return builder.allowMainThreadQueries()
            .fallbackToDestructiveMigration()
            .build()
    }

But by simply changing the path with an slash as the first character, everything works correctly!

var path = "/sdcard/Android/data/$packageName/files/rms_database.sqlite"

Upvotes: 1

tamir_sagi
tamir_sagi

Reputation: 165

Java solution:

  1. Grant permissions in Manifest
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  1. Create db (Here SofDatabase is a singleton class)
private static final String DB_NAME = "stack_overflow_db";
private static final String DB_PATH = String.format("%s/%s",
 Environment.getExternalStorageDirectory().getAbsolutePath(), DB_NAME);
    public static synchronized SofDatabase getInstance(Context aContext) {
        if (sInstance == null) {
            sInstance = Room.databaseBuilder(aContext, SofDatabase.class, DB_PATH)
                    .fallbackToDestructiveMigration()
                    .addCallback(roomCallback).build(); //adding callback from Room
        }
        return sInstance;
    }

Callback

     /**
     * Get Notified once db is created
     */
    private static final RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
            Log.i("SOF", db.getPath()); //which prints out -->  I/SOF: /storage/emulated/0/stack_overflow_db
            // add some jobs once db is created
        }
    };

Upvotes: 4

Jorge Alejandro
Jorge Alejandro

Reputation: 21

To change the db location just put the path when you build the Room database, an example for a db in your folder, in the internal storage:

fun getDatabase(context: Context, scope: CoroutineScope):   TestDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance =
                    Room.databaseBuilder(
                        context.applicationContext,
                        TestDatabase::class.java,
                        Environment.getExternalStorageDirectory().absolutePath + "/yourFolder/yourdb"
                    ).build()
                INSTANCE = instance
                return instance
            }
        }

This is a Kotlin example, if you need it in Java, just let me know. Regards.

Upvotes: 2

Benjamin Vison
Benjamin Vison

Reputation: 504

Not sure if this is what you are looking for but in my case just like @M.Yogeshwaran I needed to be able to setup an initial state of the database and work from there so I ended up doing this:

/**
 * @param context
 */
public DatabaseService(Context context) {

        File dst = context.getDatabasePath(DB_NAME);
        dst.delete();
        File src = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()+"/database.db");
        try {
            copy(src,dst);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Init the database singleton
        db = Room.databaseBuilder(context, CrediforceDatabase.class, Constants.DB_NAME).build();
}

public static void copy(File src, File dst) throws IOException {
    try (InputStream in = new FileInputStream(src)) {
        try (OutputStream out = new FileOutputStream(dst)) {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        }
    }
}

To give a bit more clarity:

  1. DB_NAME = "database.db"
  2. For testing purposes, I have the "database.db" that I want to "import" in my downloads folder, later on I will convert this code so instead the device pulls the initial database from the server.
  3. the dst.delete(); is just to delete the existing database file as I was testing things out (not sure if required)
  4. This basically translates to: Start the app > Replace the database file > build the database.
  5. Gotta be careful with the identity_hash in the room_master_table, if this is different from what's supposed to be it's not going to work.

Also, I pulled this idea from this answer: https://stackoverflow.com/a/50383879/2150472

Hope it helps anyone!

P.S, if what you need is just to be able to see the data and perform CRUD operations you can always use this plugging: https://github.com/amitshekhariitbhu/Android-Debug-Database

Upvotes: -1

Related Questions