java – Why Basic Sample project from architecture-components-samples with Room db works but this example doesn’t work?

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;
    }
}

Leave a Comment