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

jamis
The following is cross-posted from the original Ray Tracer Challenge forum, from a post by garfieldnate. I’m cross-posting it so that the...
New
edruder
I thought that there might be interest in using the book with Rails 6.1 and Ruby 2.7.2. I’ll note what I needed to do differently here. ...
New
jdufour
Hello! On page xix of the preface, it says there is a community forum "… for help if your’re stuck on one of the exercises in this book… ...
New
digitalbias
Title: Build a Weather Station with Elixir and Nerves: Problem connecting to Postgres with Grafana on (page 64) If you follow the defau...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
brunogirin
When trying to run tox in parallel as explained on page 151, I got the following error: tox: error: argument -p/–parallel: expected one...
New
hazardco
On page 78 the following code appears: <%= link_to ‘Destroy’, product, class: ‘hover:underline’, method: :delete, data: { confirm...
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
mcpierce
@mfazio23 I’ve applied the changes from Chapter 5 of the book and everything builds correctly and runs. But, when I try to start a game,...
New
dachristenson
@mfazio23 Android Studio will not accept anything I do when trying to use the Transformations class, as described on pp. 140-141. Googl...
New

Other popular topics Top

DevotionGeo
I know that these benchmarks might not be the exact picture of real-world scenario, but still I expect a Rust web framework performing a ...
New
axelson
I’ve been really enjoying obsidian.md: It is very snappy (even though it is based on Electron). I love that it is all local by defaul...
New
Exadra37
Please tell us what is your preferred monitor setup for programming(not gaming) and why you have chosen it. Does your monitor have eye p...
New
AstonJ
This looks like a stunning keycap set :orange_heart: A LEGENDARY KEYBOARD LIVES ON When you bought an Apple Macintosh computer in the e...
New
mafinar
Crystal recently reached version 1. I had been following it for awhile but never got to really learn it. Most languages I picked up out o...
New
AstonJ
Saw this on TikTok of all places! :lol: Anyone heard of them before? Lite:
New
First poster: joeb
The File System Access API with Origin Private File System. WebKit supports new API that makes it possible for web apps to create, open,...
New
husaindevelop
Inside our android webview app, we are trying to paste the copied content from another app eg (notes) using navigator.clipboard.readtext ...
New
hilfordjames
There appears to have been an update that has changed the terminology for what has previously been known as the Taskbar Overflow - this h...
New
AnfaengerAlex
Hello, I’m a beginner in Android development and I’m facing an issue with my project setup. In my build.gradle.kts file, I have the foll...
New

Sub Categories: