-1

I am in the process of creating an Android app and I have been bouncing back and forth between different implementations of my database. And for whatever reason, my app is creating databases that are from my past implementations, not the current one, in my data folder even though I have seemingly deleted all the code from my past implementations. Here is some context on how I've changed my database implementation.

  1. I first started out creating my database using SQLiteOpenHelper but quickly abandoned this implementation when I discovered the Room Persistence Library.
  2. I created a database using Room for 3 entities: SubTask, MainTask, and a junction table/entity to relate those 2 entities.
  3. I realized that creating a junction table was not the best implementation since a SubTask can only belong to one MainTask. So I scrapped the junction entity and added an attribute to SubTask to relate with MainTask. This is my current implementation and I plan to stick to it.

This is the current code I have for my database. I have decided to populate it to see if it would translate:

@Database(entities = {SubTask.class, MainTask.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {

public static final String DATABASE_NAME = "task_db";

private static AppDatabase instance;

public static synchronized AppDatabase getInstance(final Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(
                context.getApplicationContext(),
                AppDatabase.class,
                DATABASE_NAME
        ).fallbackToDestructiveMigration().addCallback(roomCallback).build();
    }

    return instance;
}

public abstract SubTaskDao getSubTaskDao();

public abstract MainTaskDao getMainTaskDao();

//TESTING TO POPULATE DATABASE
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
        new PopulateDbAsyncTask(instance).execute();
    }
};

private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
    private MainTaskDao mainTaskDao;
    private SubTaskDao subTaskDao;

    private PopulateDbAsyncTask(AppDatabase db) {
        mainTaskDao = db.getMainTaskDao();
        subTaskDao = db.getSubTaskDao();
    }

    @Override
    protected Void doInBackground(Void... voids) {
        Calendar date1 = Calendar.getInstance();
        date1.set(2019, 2, 10);
        mainTaskDao.insertMainTasks(new MainTask("School Assignments", 0xFF0000, date1));

        Calendar date2 = Calendar.getInstance();
        date2.set(2019, 2, 8);
        subTaskDao.insertSubTasks(new SubTask("Read database book", date2, 1));

        Calendar date3 = Calendar.getInstance();
        date3.set(2019, 2, 6);
        subTaskDao.insertSubTasks(new SubTask("Read OS book", date3, 1));

        return null;
    }
}
}

When I build and open my app for the first time, it crashes and I get the following in the log:

2019-03-05 19:53:36.241 20085-20106/com.myname.divideandconquer E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
Process: com.myname.divideandconquer, PID: 20085
java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
    at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:135)
    at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:115)
    at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:151)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:409)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:298)
    at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:96)
    at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
    at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:233)
    at com.johnsorhannus.divideandconquer.room.SubTaskDao_Impl$4.compute(SubTaskDao_Impl.java:159)
    at com.johnsorhannus.divideandconquer.room.SubTaskDao_Impl$4.compute(SubTaskDao_Impl.java:145)
    at android.arch.lifecycle.ComputableLiveData$2.run(ComputableLiveData.java:100)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)

When I look in the Device File Explorer, I see the following for my app: Image 1. task_db is the database being created with Room. I opened this database with a third-party app and this file contains tables for 3 entities, not 2, so this appears to be from implementation (2). taskManager is the database that I created using SQLiteOpenHelper (implementation 1), and it is populated with data that I had hardcoded into the database. I am baffled as to why this database exists. I have deleted all my code from this implementation. I have even searched my entire project for taskManager to see if I ever gave a database this name anywhere in my code. Nothing!

When I go into the app settings and clear storage and I run the app again on Android Studio, I get no error in the log and I get the following in my Device File Explorer: Image 2. task_db is completely empty. No tables at all, so I am not exactly sure whether this is from implementation (2) or (3). This is also surprising because I expected the database to be populated with the values that I hardcoded.

I have no idea why these databases are being created even though I have deleted code from my past two implementations. There no longer contains any trace of code from SQLiteOpenHelper and I have deleted the Dao and Entity for the junction table. Any clue as to what is going on?

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
John S.
  • 71
  • 5

2 Answers2

0

Look at the error. it is showing you the reason of error.

java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.

So you have changed some schema in you code. So simply change the version of database from 1 to 2.

Database(entities = {SubTask.class, MainTask.class}, version = 2)
Keyur Nimavat
  • 3,595
  • 3
  • 13
  • 19
  • I have done this and it works, but the junction table still exists in `task_db` and it is not populated with any data. I see 2 other `task_db` database files, but they are encrypted. And I'm still not sure why `taskManager` is created when the app is first opened since the code that creates that does not exist anymore. – John S. Mar 06 '19 at 03:15
0

you have to uninstall the app (or delete the files from the internal storage), else the Room schema of the previous version will persist (just alike it would persist, when having created these files with the SQLiteOpenHelper) and then the new schema will be compared to the old schema. increasing the version number only makes sense for apps released already, when intending to create a migration.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • I have tried both of these approaches. The problem persists when I uninstall the app but it stops crashing when I delete files from internal storage. A new room database is then created that is totally empty with no tables existing within it. I still don't understand why my `SQLiteOpenHelper` table `taskManager` is created when the app is first launched. The code for this does not exist anymore. – John S. Mar 06 '19 at 03:28
  • @JohnS. the `Room` annotations might be messed up. there might be one class annotated with `tableName = "taskManager"`... or these two `*.db` files or one? It somehow makes no sense, that a schema could change, while there are no tables. one can even define the location of the schema json; no clue what the default location is. – Martin Zeitler Mar 06 '19 at 03:38
  • There is no trace of `taskManager` anywhere in my code. `task_db` and `taskManager` are two separate `.db` files. A json file is generated for each version of the room database and there are two tables listed in the file. I did a little more experimenting and found that after I delete the files from internal storage, if I increase the version number of the database, I get `task_db` with tables but no data populated inside of them. – John S. Mar 06 '19 at 04:25
  • I've done some more experimenting. I have been testing on a physical device the entire time, so I tried to run the app on an emulator device to see if the same thing was happening. When I first launched the app on the emulator, it worked! And `taskManager` was not created. `task_db`, however, had no tables and was not populated even though `doInBackground` was called according to my log. For whatever reason, `taskManager` is created only when I run the app on my physical device. Any ideas on why this is happening? – John S. Mar 06 '19 at 15:51
  • @JohnS. if that hardware device has multi-user ...select "uninstall for all users". that's tacked away in Settings > Applications > select your app ...top right menu dots. there probably is no other logical explanation for that... the regular uninstall button only uninstalls it for the current user - which leaves the database behind. – Martin Zeitler Mar 06 '19 at 16:54
  • I don't have multiple users on my phone. But when I do clear the storage and uninstall the app, I see that there is no trace of my app's data in my device explorer. So it is not being left behind. It's very strange why this database is being created. – John S. Mar 06 '19 at 17:28
  • @JohnS. you don't have to have multiple users, because you and the guest account are already multi-users (it's enough when it is being supported)... and if that buttons is there, just click it. On my `XT1100` (Android 7.1.1) I have it, on my `XT1900` (Android 9.0.0) I don't. it's quite a common source for this type of confusion. – Martin Zeitler Mar 06 '19 at 17:30
  • I have a Pixel 3 running Android Pie and I don't see it. – John S. Mar 06 '19 at 17:35
  • @JohnS. don't think it has it. nevertheless think that this database file somehow has to survive the uninstall - and not that it is being created, without the least code or annotations which would cause that. simply changing the name of that file would also cause it to be forgotten about - because then it will behave, as if never was there. this might be a halfhearted solution, but it appears to be something workable. and I think that it might restored it from a backup ...and the emulator has no Google account added !! – Martin Zeitler Mar 06 '19 at 17:53
  • 1
    see this [answer](https://stackoverflow.com/a/53348625/549372) of mine ...in order to prevent this in the future. – Martin Zeitler Mar 06 '19 at 17:56