6

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?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Gaju Kollur
  • 2,046
  • 5
  • 23
  • 47
  • There is no reason to copy to an external folder. Room is meant to be read from internal app memory only. If you need an external SQLite file for your app, then you need to use SQLiteOpenHelper, AFAIK. If you only want to view the content, I already linked you this https://stackoverflow.com/questions/44429372/view-contents-of-database-created-with-room-persistence-library – OneCricketeer Feb 21 '18 at 11:21
  • @cricket_007 i want to modify db directly adding some dummy data to tables using sqlite browser ..not only viewing – Gaju Kollur Feb 21 '18 at 11:33
  • Okay, well, I've not found any references that external SQLite files can't be read or imported into Room, so if you find a way, feel free to let me know. – OneCricketeer Feb 21 '18 at 11:36
  • have you done it – M.Yogeshwaran Apr 13 '18 at 06:26
  • @M.Yogeshwaran No ..no – Gaju Kollur Apr 13 '18 at 06:38
  • then what you did , i need like i download db file google drive and need to work from that – M.Yogeshwaran Apr 13 '18 at 06:39
  • You can generate the DB in any location that your app has access to, by specifying an absolute path as the third ("name") parameter of `Room.databaseBuilder`. Why are people saying that you can't? – Andrew Koster Sep 27 '19 at 14:49

4 Answers4

4

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
        }
    };
tamir_sagi
  • 155
  • 1
  • 10
2

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.

  • 3
    It doesn't work for me --> java.lang.IllegalArgumentException: File storage/sdcard0/Download/database/example contains a path separator. Using Room version 1.1.1. On a Huawei P8 Lite. – marcos E. Mar 04 '19 at 16:50
1

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"
pjaaar
  • 71
  • 1
  • 6
-1

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

Benjamin Vison
  • 469
  • 9
  • 20