'I can't load a ready database in my room database although I put it in Assets folder

Room.databaseBuilder(getApplicationContext(), UserDatabase.class,"users_db")
                .createFromAsset("users.db")
                .build();

        UserDatabase db = Room.databaseBuilder(getApplicationContext(),
                UserDatabase.class,"users_db").allowMainThreadQueries()
                .fallbackToDestructiveMigration()
                .addMigrations()
                .build();

Even I tried to add as a file to prepopulate as "createFromFile" with the following code

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromFile(new File("mypath"))
    .build();


Solution 1:[1]

If the above is the only code then unless you try to access the database, the database will not be created. That is just getting an instance of the built database just creates an instance that is ready to open the database.

So if you have, for example :-

UserDatabase db = Room.databaseBuilder(getApplicationContext(),
    UserDatabase.class,"users_db").allowMainThreadQueries()
    .createFromAsset("users.db")
    .build();

Then it is not until, for example, you did

SupportSQLiteDatabase accessedDatabase = db.getOpenHelper().getWritableDatabase();

That an attempt to open the database (in the case of no database existing, then an attempt to create the database, and in the case of createFromAsset the create database will then attempt the copy from the asset).

Typically you would not get a SupportSQliteDatabase but would simply try to access the database via the Dao's ( i.e. the methods in the interfaces or abstract classes that are annotated with @Dao).


Demonstration

Consider the following :-

An existing database from an external source (Navicat in the example) :-

enter image description here

  • just a single table and therefore @Entity annotated class will be required.
  • as can be seen it has 3 users.
  • IMPORTANT the schema MUST adhere to what Room expects, which has limitations

The database is copied to the assets folder as users.db :-

enter image description here

An @Entity annotated class User (so the table name will be User) :-

@Entity
class User {
   @PrimaryKey
   Long id = null;
   String username;
}
  • 2 columns
    • id which is the Primary Key and as the type is Long then the column type must be INTEGER
    • username, as it's a String then column type MUST be TEXT, as there is no @NonNUll annotation then NOT NULL should not be coded (if it were then the schema room expects would not be as above)

An @Dao annotated class UserDao :-

@Dao
interface UserDao {
    @Insert
    long insert(User user);
    @Query("SELECT * FROM user")
    List<User> getAllUsers();
}

An @Database annotated class UserDatabase :-

@Database(entities = {User.class}, version = 1,exportSchema = false)
abstract class UserDatabase extends RoomDatabase {
    abstract UserDao getUserDao();

    private static volatile UserDatabase instance = null;
    static UserDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(context,UserDatabase.class,"users_db")
                    .allowMainThreadQueries()
                    .createFromAsset("users.db")
                    .build();
        }
        return instance;
    }
}
  • note the getInstance() method (see the activity code that follows)

Putting it all together in an activity

First a shortened version that does not access the database but just gets an instance of the UserDatabase :-

public class MainActivity extends AppCompatActivity {

    UserDatabase db;
    UserDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = Room.databaseBuilder(this,UserDatabase.class,"users_db")
                .allowMainThreadQueries()
                .createFromAsset("users.db")
                .build();
        dao = db.getUserDao(); //<<<<< WILL NOT OPEN THE DATABASE
        
    }
}

When the above is run AppInspection shows nothing.

However, using :-

public class MainActivity extends AppCompatActivity {

    UserDatabase db;
    UserDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = Room.databaseBuilder(this,UserDatabase.class,"users_db")
                .allowMainThreadQueries()
                .createFromAsset("users.db")
                .build();
        dao = db.getUserDao(); //<<<<< WILL NOT OPEN THE DATABASE
        //db.getOpenHelper().getWritableDatabase(); //<<<<< Force an open of the database

        //<<<<< WILl OPEN THE DATABASE
        for(User u: dao.getAllUsers()) {
            Log.d("USERINFO","UserName is" + u.username + " ID is " + u.id);
        }

    }

    /*
        Example of using the singleton (not called)
     */
    void unusedFromExample() {
        UserDatabase db = UserDatabase.getInstance(this);
        UserDao dao = db.getUserDao();
        /// etc
    }
}

and the log includes (as expected) :-

D/USERINFO: UserName isuser1 ID is 1
D/USERINFO: UserName isuser2 ID is 2
D/USERINFO: UserName isuser3 ID is 2000

And AppInspection shows the database and that it has ben copied.

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1