0

I am upgrading an app from targeting sdk 25 to targeting sdk 29, all the tables in my room database have a @PrimaryKey annotation but were not annotated with @NonNull. Now that I am targeting sdk 29, room is requiring the @NonNull annotation, unfortunately that causes my app to crash on startup unless I do a fresh install.

Error it causes without fresh install:

java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:318)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)
 Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

I figured that was because my database had to be migrated because it works on a fresh install.

So far I have found some helpful stack overflow answers such as this one.

But that would require me to rewrite every table in my database and making sure I bring all the indices over as well. I do not want to have to do this as I am sure I will miss something and it will create multiple bugs.

Is there a simpler way to do a room migration where I just add the @NonNull annotation to all my primary keys?

Alternatively I have seen mention of grabbing the schema from the SQLite tables that would encapsulate all the indices into a query, but I do not know how to get that schema in my migration.

Example class after I have added NonNull tag:

@Entity(tableName = "FavoriteTrip"
    , indices = { @Index("tripPlanId") }
    , foreignKeys = @ForeignKey(entity = TripPlan.class, parentColumns = "id", childColumns = "tripPlanId"))
public class FavoriteTrip {

    @PrimaryKey @NonNull
    private String id = UUID.randomUUID().toString();
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
TheHeuman
  • 152
  • 1
  • 2
  • 15

1 Answers1

0

Is there a simpler way to do a room migration where I just add the @NonNull annotation to all my primary keys?

I believe that there is but haven't actually played with it that much (just a quick foray and found that you are still left with creating the Entities to correctly match the tables). That is to let ROOM convert the database (you might have to delete the room_master_table) and that is to use one of the recently added createFrom methods.

These will convert the database to one that is acceptable to room BUT as far as I am aware it does not create the Entities, which I've seen has presented quite a few headaches due to the expected .......... found ....... being quite difficult to read.

Another option is something that I've been playing with which converts databases and additionally generates basic Entitity/Dao and Database code (Java). This tool can be found at RoomExistingSQLiteDBConverter which has links the source on github.

  • As a very quick overview,

:-

  1. you run the App (probably in an AS emulator, although could be on a real device).

  2. Copy the database into any (bar 1 reserved folder) folder in public external storage (before or when the App is running, if the latter then click refresh button).

  3. Have a look at the various listed components for potential highlighted issues.
  4. When happy click the Convert button.
  5. Copy the database ready for it to be imported (typically as an asset in to the assets folder) to the App being developed/changed.
  6. Copy the code into the appropriate folders in the App.
  7. Edit the code to bring in the appropriate imports.
  8. Write code to copy the database from the assets folder.
  9. Test.
MikeT
  • 51,415
  • 16
  • 49
  • 68