I’m working on android project with room db and I’m getting crazy about this problem. The db doesn’t create what ever I try. No errors, nothing in Logcat and nothing also while debugging. I did exactly the same as Basic Sample. I have another project based on the same exact sample and it’s working there!!. but with this new project the db doesn’t create. I checked every thing from Gradle dependencies to project code to Dao queries and every thing the same nothing strange. I just need to know what’s the difference and why this is happening. what will be the root cause which prevent the creation of room database silently without any error or notification
build.Gradle (Module)
plugins {
id 'com.android.application'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.bact.hr"
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lint {
abortOnError false
}
buildFeatures {
dataBinding true
}
namespace 'com.bact.hr'
}
dependencies {
// UI
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.fragment:fragment:1.4.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha02'
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
// Room components
implementation 'androidx.room:room-runtime:2.5.0-alpha02'
annotationProcessor 'androidx.room:room-compiler:2.5.0-alpha02'
implementation 'androidx.room:room-paging:2.5.0-alpha02'
// https://mvnrepository.com/artifact/androidx.paging/paging-runtime
implementation 'androidx.paging:paging-runtime:3.2.0-alpha01'
// Lifecycle components
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
//implementation 'androidx.lifecycle:lifecycle-viewmodel:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
// Android Testing Support Library's runner and rules
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:core:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.room:room-testing:2.5.0-alpha02'
androidTestImplementation 'androidx.arch.core:core-testing:2.1.0'
// Espresso UI Testing
androidTestImplementation ("androidx.test.espresso:espresso-core:3.4.0", {
exclude group: 'com.android.support', module: 'support-annotations'})
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
// Resolve conflicts between main and test APK:
androidTestImplementation 'androidx.appcompat:appcompat:1.4.2'
androidTestImplementation 'com.google.android.material:material:1.6.1'
//other
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
}
I have 2 Dao classes for 2 Entities. now My AppDatabase Class looks like this.
@Database(entities = {EmployeeEntity.class, EmployeeFtsEntity.class, EmployeeInfoEntity.class, EmployeeInfoFtsEntity.class}, version = 2)
@TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase {
// "volatile" The value of an attribute is not cached thread-locally, and is always read from the "main memory"
private static volatile AppDatabase sInstance;
@VisibleForTesting
public static final String DATABASE_NAME = "HRDB";
public abstract EmployeeInfoDao EmployeeInfoDao();
public abstract EmployeeDao EmployeeDao();
private final MutableLiveData<Boolean> mIsDatabaseCreated = new MutableLiveData<>();
public static AppDatabase getInstance(final Context context, final AppExecutors executors) {
if (sInstance == null) {
synchronized (AppDatabase.class) {
if (sInstance == null) {
sInstance = buildDatabase(context.getApplicationContext(), executors);
sInstance.updateDatabaseCreated(context.getApplicationContext());
}
}
}
return sInstance;
}
/**
* Build the database. {@link Builder#build()} only sets up the database configuration and
* creates a new instance of the database.
* The SQLite database is only created when it's accessed for the first time.
*/
@NonNull
private static AppDatabase buildDatabase(final Context applicationContext, final AppExecutors executors) {
Log.d("buildDatabase","buildDatabase has been Invoked.");
return Room.databaseBuilder(applicationContext, AppDatabase.class, DATABASE_NAME)
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Log.d("ONCREATE","Database has been created.");
executors.diskIO().execute(() -> {
// Add a delay to simulate a long-running operation
addDelay();
AppDatabase database = AppDatabase.getInstance(applicationContext, executors);
// Generate the data for pre-population
List<EmployeeEntity> Employees = DataGenerator.generateEmployee();
List<EmployeeInfoEntity> EmployeesInfo = null;
try {
EmployeesInfo = DataGenerator.generateEmployeeInfo();
} catch (ParseException e) {
e.printStackTrace();
}
insertData(database, Employees, EmployeesInfo);
// notify that the database was created and it's ready to be used
database.setDatabaseCreated();
});
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
Log.d("ONOPEN","Database has been opened.");
}
})
.addMigrations(MIGRATION_1_2)
.build();
}
private void updateDatabaseCreated(@NonNull Context applicationContext){
if (applicationContext.getDatabasePath(DATABASE_NAME).exists()) {
setDatabaseCreated();
}
}
private void setDatabaseCreated(){
mIsDatabaseCreated.postValue(true);
}
private static void insertData(@NonNull final AppDatabase database, final List<EmployeeEntity> Emps,
final List<EmployeeInfoEntity> EmpsInfo) {
database.runInTransaction(() -> {
database.EmployeeDao().insertAllEmployees(Emps);
database.EmployeeInfoDao().insertAllEmployeesInfo(EmpsInfo);
});
}
private static void addDelay() {
try {
Thread.sleep(4000);
} catch (InterruptedException ignored) {
}
}
public LiveData<Boolean> getDatabaseCreated() {
return mIsDatabaseCreated;
}
private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
Log.d("MIGRATE","DATABASE MIGRATE INVOKED");
/* database.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `employee_Fts` USING FTS4(" +
" `username` TEXT, `password` TEXT, content= `employee_info` )");
database.execSQL("INSERT INTO employee_Fts (" +
" `rowid`, `username`, `password`) " +
" SELECT `id`, `username`, `password`" +
" FROM employee");*/
database.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `employee_info_Fts` USING FTS4(" +
" `firstname` TEXT,`lastname` TEXT, `father` TEXT, `birthdate` Date," +
" `mobile_number` TEXT, `academic_specialization` TEXT," +
" `department` TEXT, content= `employee_info` )");
database.execSQL("INSERT INTO employee_info_Fts (" +
" `rowid`, `firstname`, `lastname`, `father`, `birthdate`," +
" `mobile_number`,`academic_specialization`, `department`) "
+ "SELECT `id`, `firstname`, `lastname`, `father`, `birthdate`," +
" `mobile_number`, `academic_specialization`, `department`" +
" FROM employee_info");
}
};
}
DataRepository Class Constructor and getInstance() method
public class DataRepository {
private static volatile DataRepository sInstance;
private final AppDatabase mDatabase;
private final MediatorLiveData<List<EmployeeInfoEntity>> mObservableEmployeesInfo;
private final MediatorLiveData<List<EmployeeEntity>> mObservableEmployees;
private DataRepository(final AppDatabase database) {
mDatabase = database;
mObservableEmployeesInfo = new MediatorLiveData<>();
mObservableEmployees = new MediatorLiveData<>();
mObservableEmployeesInfo.addSource(mDatabase.EmployeeInfoDao().loadAllEmployeesInfo(),
empInfoEntities -> {
if (mDatabase.getDatabaseCreated().getValue() != null) {
mObservableEmployeesInfo.postValue(empInfoEntities);
}
});
mObservableEmployees.addSource(mDatabase.EmployeeDao().loadAllEmployees(),
empEntities -> {
if (mDatabase.getDatabaseCreated().getValue() != null) {
mObservableEmployees.postValue(empEntities);
}
});
}
public static DataRepository getInstance(final AppDatabase database) {
if (sInstance == null) {
synchronized (DataRepository.class) {
if (sInstance == null) {
sInstance = new DataRepository(database);
}
}
}
return sInstance;
}
DataGenerator Class
public class DataGenerator {
private static final String[] usernames = new String[]{"Frank", "Jack"};
private static final String[] passwords = new String[]{"vf@621789", "xcb8x123"};
private static final String[] Firstname = new String[]{"Frank", "Jack"};
private static final String[] Lastname = new String[]{"Adam", "Joe"};
private static final String[] Father = new String[]{"Peter", "Zack"};
private static final List<Date> Birthdate = new ArrayList<>();
private static final String[] Mobile = new String[]{"+12356251234", "+14528963547"};
private static final String[] Acc_spec = new String[]{"Engineer", "Accounting"};
private static final String[] Dep = new String[]{"IT Department", "Accounting"};
@NonNull
public static List<EmployeeEntity> generateEmployee(){
List<EmployeeEntity> Employees = new ArrayList<>(usernames.length);
for (int i = 0; i < usernames.length; i++) {
EmployeeEntity Employee = new EmployeeEntity();
Employee.setUsername(usernames[i]);
Employee.setPassword(passwords[i]);
Employees.add(Employee);
}
return Employees;
}
@NonNull
public static List<EmployeeInfoEntity> generateEmployeeInfo() throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("dd/M/yyyy", Locale.ENGLISH);
Birthdate.add(formatter.parse("21/05/2022"));
Birthdate.add(formatter.parse("20/06/2022"));
List<EmployeeInfoEntity> EmployeesInfo = new ArrayList<>(Firstname.length);
for (int i = 0; i < Firstname.length; i++) {
EmployeeInfoEntity EmployeeInfo = new EmployeeInfoEntity();
EmployeeInfo.setFname(Firstname[i]);
EmployeeInfo.setLname(Lastname[i]);
EmployeeInfo.setFather(Father[i]);
EmployeeInfo.setBirth(Birthdate.get(i));
EmployeeInfo.setMobile(Mobile[i]);
EmployeeInfo.setAcc_spec(Acc_spec[i]);
EmployeeInfo.setDep(Dep[i]);
EmployeesInfo.add(EmployeeInfo);
}
return EmployeesInfo;
}
}