jskubick

jskubick

Kotlin and Android Development featuring Jetpack: SQLite database not removed by uninstallation of PennyDrop

This isn’t errata per se, but I discovered something unexpected while working through Chapter 5. I’m not sure whether I just misunderstood how SQLite works, or whether it’s a bug in Arctic Fox (Android Studio 2020.3.1 patch 2), the x86 Emulator, or the Android 11 ROM it’s running, but it appears that uninstalling PennyDrop does NOT blow away the underlying SQLite database.

How to replicate:

  1. Build and run PennyDrop in the emulator using the chapter 5 code from the .zip file

  2. Play a game or two, giving the player a distinctive name you’ll recognize later.

  3. Kill PennyDrop in the emulator by clicking the red ‘stop’ icon in Android Studio.

  4. In the Emulator, go to Settings → Apps, find PennyDrop, and uninstall it.

  5. Go back to Android Studio, and re-launch PennyDrop by clicking the green ‘play’ icon. It’ll re-deploy and start.

  6. Attempt to start a new game, and observe it crash with a SQLiteConstraintException (UNIQUE constraint failed on primary key)

It’s been a few years since I’ve used “raw” SQLite, so I don’t remember offhand whether it defaults to putting your database files in the app’s private data dir, or whether the app is expected to tell it where to put them (and the private data dir is simply an obvious & sensible place)… but it looks like Jetpack Room does NOT put its SQLite data files there, and instead puts them somewhere else that doesn’t automatically get blown away when the app gets uninstalled.

Of course, it’s also possible that Google built a custom ROM for the emulator that intentionally leaves the data dir of uninstalled apps behind for forensics purposes, or that it’s actually a developer setting somewhere that I’ve just overlooked for years. It might also be an outright bug in Arctic Fox, or Room 2.3.0, or all the above and more.

Either way, the only solution I’ve found is to modify PennyDropDatabase.kt as follows:

  1. Increase the ‘version’ number in the @Database annotation:
    @Database(
        entities = [Game::class, Player::class, GameStatus::class],
->      version = 2,
        exportSchema = false
    )
  1. Add a call to fallbackToDestructiveMigration() to the builder:
    val instance = Room.databaseBuilder(
        context,
        PennyDropDatabase::class.java,
        "PennyDropDatabase" )
->      .fallbackToDestructiveMigration()
        .addCallback(object : RoomDatabase.Callback() {
        override fun onCreate(db : SupportSQLiteDatabase) {
        // ...

As I understand it, the call to fallbackToDestructiveMigration() basically tells it, “if the database version changes, blow away the old one and rebuild it from scratch according to the new specs without attempting to migrate anything”.

Given everything I’ve always thought I’ve known about the implied behavior of Android apps when uninstalled, the persistence of Room-created SQLite databases after the creator’s uninstallation is pretty shocking, and almost has to be a bug in Room unless it’s just the side effect of a developer option I overlooked. Otherwise, this would leave the door open to a SERIOUS (flash) memory leak for an Android device… a misbehaving app could create a multi-gigabyte Room database that would persist even after the app that created it were uninstalled, and would (AFAIK) be impossible to remove by hand unless the device were rooted.

Update:

According to this post at StackOverflow (android - Remove room database on app uninstall - Stack Overflow), the android:allowBackup=“true” in AndroidManifest.xml might be the root of the problem. Apparently, SQLite databases are one of the things that automatically get backed up.

From what I’ve read so far, once the backup gets made, deleting it is “a pain”, because the backups are almost viral. Merely changing allowBackups to false will prevent future backups, but won’t prevent the existing backup from getting auto-restored in perpetuity upon reinstallation. It looks like the only official way to purge the backup once it has been created is to make the app uninstallation-aware, and add code to the DAO class to explicitly drop the tables as part of the uninstallation process.

Where Next?

Popular Pragmatic Bookshelf topics Top

telemachus
Python Testing With Pytest - Chapter 2, warnings for “unregistered custom marks” While running the smoke tests in Chapter 2, I get these...
New
ianwillie
Hello Brian, I have some problems with running the code in your book. I like the style of the book very much and I have learnt a lot as...
New
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
herminiotorres
Hi @Margaret , On page VII the book tells us the example and snippets will be all using Elixir version 1.11 But on page 3 almost the en...
New
fynn
This is as much a suggestion as a question, as a note for others. Locally the SGP30 wasn’t available, so I ordered a SGP40. On page 53, ...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
Henrai
Hi, I’m working on the Chapter 8 of the book. After I add add the point_offset, I’m still able to see acne: In the image above, I re...
New
tkhobbes
After some hassle, I was able to finally run bin/setup, now I have started the rails server but I get this error message right when I vis...
New
a.zampa
@mfazio23 I’m following the indications of the book and arriver ad chapter 10, but the app cannot be compiled due to an error in the Bas...
New
bjnord
Hello @herbert ! Trying to get the very first “Hello, Bracket Terminal!" example to run (p. 53). I develop on an Amazon EC2 instance runn...
New

Other popular topics Top

AstonJ
What chair do you have while working… and why? Is there a ‘best’ type of chair or working position for developers?
New
ohm
Which, if any, games do you play? On what platform? I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
New
AstonJ
We have a thread about the keyboards we have, but what about nice keyboards we come across that we want? If you have seen any that look n...
New
New
AstonJ
I have seen the keycaps I want - they are due for a group-buy this week but won’t be delivered until October next year!!! :rofl: The Ser...
New
Exadra37
Oh just spent so much time on this to discover now that RancherOS is in end of life but Rancher is refusing to mark the Github repo as su...
New
AstonJ
Continuing the discussion from Thinking about learning Crystal, let’s discuss - I was wondering which languages don’t GC - maybe we can c...
New
gagan7995
API 4 Path: /user/following/ Method: GET Description: Returns the list of all names of people whom the user follows Response [ { ...
New
PragmaticBookshelf
Programming Ruby is the most complete book on Ruby, covering both the language itself and the standard library as well as commonly used t...
New
AstonJ
This is a very quick guide, you just need to: Download LM Studio: https://lmstudio.ai/ Click on search Type DeepSeek, then select the o...
New

Sub Categories: