I am trying to prepopulate a database as described in this Room documentation.
It says to
call the createFromAsset() method from your RoomDatabase.Builder object before calling build()
and shows the following code:
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromAsset("database/myapp.db")
.build();
My question is, where does this code go? Following the steps for getting started with Room, I've created a Data entity class, a Data access object interface, and a Database class. This code should run just once, on install or perhaps first-time startup. I do not want it to run each time the app starts, and definitely not each time my main activity is created.
Where exactly do I place the Room.databaseBuilder(...
code to initialize the database?
CodePudding user response:
The databaseBuilder
doesn't actually initialise the database, rather it returns an AppDatabase
object (in your case). When that returned AppDatabase
object is used to access the database (typically via one of the @Dao annotated functions) then it will either open the database if it exists or initialise(create) it.
Having the .createFromAsset means that the create will copy the file from the asset rather than create the database according to the classes specified as entities in the @Database annotation.
In short once the database exists, it exists, it will not be initialised/created, every time the App is run.
Often a singleton approach is used, thus you have a single AppDatabase object that you retrieve throughout the App.
My question is, where does this code go?
If using a singleton approach then probably in the AppDatabase class.
e.g.
@Database(
entities = {/* the @Entity annotated classes here */},
version = 1,
exportSchema = false
)
abstract class AppDatabase extends RoomDatabase {
abstract AllDAO getAllDAO(); /* one for each @Dao annotated interface or abstract class */
private static volatile AppDatabase instance = null;
static AppDatabase getInstance(Context context) {
if (instance == null) {
instance /* i.e. an instance of the AppDatabase */ = Room.databaseBuilder(
context,
AppDatabase.class,
"Sample.db"
)
.createFromAsset("database/myapp.db")
.build();
}
return instance;
}
}
- note this doesn't go into the issues/complexities of singleton's
So with the above in an activity/fragment you simply use the getInstance
method. This will, invoked the databaseBuilder just the once throughout.
Only the very first time it is invoked for the lifetime of the database, will the database file be copied from the assets folder. Subsequent builds will open the existing database. Whilst the App is running the build is not repeated but instead the already built AppDatabase object is returned.
In an activity (probably many activities) you could have, as an example :-
public class MainActivity extends AppCompatActivity {
AppDatabase sampleDb;
AllDAO dao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sampleDb = AppDatabase.getInstance(this);
dao = sampleDb.getAllDAO();
/* AT THIS STAGE THE DATABASE WILL NOT HAVE BEEN INITIALISED */
/* Either of the following would initialise the database */
/* NOTE following would fail as trying to access on the main thread, could use .allowMainThreadQueries in databaseBuilder */
dao.????????; /* use one of the functions from the respective @Dao annotated interface or abstract class */
/* OR FORCE an OPEN e.g. */
SupportSQLiteDatabase openSampleDb = sampleDb.getOpenHelper().getWritableDatabase();
/* Note that you could force an open in the getInstance method if wanted, but typically not so */
....
}
....
}