Solution 1 :
You need to register at least one observer to any of dao methods that returns LiveData.When observer is registered your roomCallback onCreate will get called.
To remove those nested spaghetti code you could use AsyncTask to prepopulate db, so it would look something like this:
public static synchronized ProjectDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(),
ProjectDatabase.class, DATABASE_NAME)
.addCallback(roomCallback)
.build();
}
return instance;
}
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Log.d(TAG, "callback was called.");
new PopulateDbAsyncTask(instance).execute();
}
};
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void>
{
private ProjectDao projectDao;
private PopulateDbAsyncTask(ProjectDatabase db){
projectDao=db.projectDao();
}
@Override
protected Void doInBackground(Void... voids) {
List<Project> projects = DataGenerator.generateProjects();
projectDao.insertAll(projects )
return null;
}
}
}
Problem :
I am very stuck on this. I am following Googles “ArchitectureComponentsBasic1”, which you can import into Android Studio by going to File -> New -> Import Sample. I’ve also followed the suggestions provided by Maxim in this SO article. Nothing is working though. How can I get the OnCreate callback to run so I can pre-populate my database?
Database: Please note that I am running the executor in my buildDatabase
method to try and run a dummy query to get getWritableDatabase()
to run based on the SO linked above. This does not work.
version = 1,
exportSchema = false)
public abstract class ProjectDatabase extends RoomDatabase {
private final MutableLiveData<Boolean> isDatabaseCreated = new MutableLiveData<>();
private static ProjectDatabase instance;
private static final String DATABASE_NAME = "project.db";
private static final String TAG = ProjectDatabase.class.getSimpleName();
public abstract ProjectDao projectDao();
public static ProjectDatabase getInstance(final Context context, final AppExecutors appExecutors) {
if (instance == null) {
synchronized (ProjectDatabase.class) {
if (instance == null) {
instance = buildDatabase(context.getApplicationContext(), appExecutors);
instance.updateDatabaseCreated(context.getApplicationContext());
}
}
}
return instance;
}
private static ProjectDatabase buildDatabase(final Context appContext, final AppExecutors appExecutors) {
Log.d(TAG, "building database.");
ProjectDatabase db = Room.databaseBuilder(appContext, ProjectDatabase.class, DATABASE_NAME)
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Log.d(TAG, "callback was called.");
appExecutors.diskIO().execute(() -> {
ProjectDatabase database = ProjectDatabase.getInstance(appContext, appExecutors);
List<Project> projects = DataGenerator.generateProjects();
Log.d(TAG, "project data: " + projects.get(0).getTitle());
insertData(database, projects);
database.setDatabaseCreated();
});
}
})
.build();
appExecutors.diskIO().execute(new Runnable() {
@Override
public void run() {
Log.d(TAG, "populate database");
db.projectDao().populateDatabase();
}
});
return db;
}
/**
* Check whether the database already exists and expose it via {@link #getDatabaseCreated()}
*/
private void updateDatabaseCreated(final Context context) {
if (context.getDatabasePath(DATABASE_NAME).exists()) {
setDatabaseCreated();
}
}
private void setDatabaseCreated(){
Log.d(TAG, "database created");
isDatabaseCreated.postValue(true);
}
private static void insertData(final ProjectDatabase database, final List<Project> projects) {
database.runInTransaction(() -> {
database.projectDao().insertAll(projects);
});
}
Project DAO
@Dao
public interface ProjectDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insertAll(List<Project> projects);
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(Project project);
@Query("SELECT * FROM project")
LiveData<List<Project>> loadAllProjects();
@Query("SELECT * FROM project WHERE is_favorite = 1")
LiveData<Project[]> getAllFavorites();
@Query("SELECT is_favorite FROM project WHERE id = :projectId")
int isFavorite(int projectId);
@Query("UPDATE project SET is_favorite = 1 WHERE id = :projectId")
int addToFavorites(int projectId);
@Query("UPDATE project SET is_favorite = 0 WHERE id = :projectId")
int removeFromFavorites(int projectId);
// Dummy query needed to activate the Room callback method to prepopulate the database
@Query("SELECT * from project")
LiveData<Project> populateDatabase();
}
Comments
Comment posted by Zain
Hi, I can understand that your
Comment posted by Michael
@Zain yes, the Callback is not called. From what I’ve read, the onCreate callback is not called until you perform the first operation on the database. That’s why I added db.projectDao.populateDatabase, which is designed to do a database operation with dummy data. But even though that gets called, the onCreate callback still is not called.
Comment posted by Zain
can you try to call
Comment posted by Michael
That doesn’t really have anything to do with the issue. The problem is the onCreate callback is not getting called.
Comment posted by out-of-box way for prepopulating in Room
Don’t you want to use