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

brianokken
Many tasks_proj/tests directories exist in chapters 2, 3, 5 that have tests that use the custom markers smoke and get, which are not decl...
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
JohnS
I can’t setup the Rails source code. This happens in a working directory containing multiple (postgres) Rails apps. With: ruby-3.0.0 s...
New
alanq
This isn’t directly about the book contents so maybe not the right forum…but in some of the code apps (e.g. turbo/06) it sends a TURBO_ST...
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
jonmac
The allprojects block listed on page 245 produces the following error when syncing gradle: “org.gradle.api.GradleScriptException: A prob...
New
kolossal
Hi, I need some help, I’m new to rust and was learning through your book. but I got stuck at the last stage of distribution. Whenever I t...
New
andreheijstek
After running /bin/setup, the first error was: The foreman' command exists in these Ruby versions: That was easy to fix: gem install fore...
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

Other popular topics Top

PragmaticBookshelf
Ruby, Io, Prolog, Scala, Erlang, Clojure, Haskell. With Seven Languages in Seven Weeks, by Bruce A. Tate, you’ll go beyond the syntax—and...
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
Continuing the discussion from Thinking about learning Crystal, let’s discuss - I was wondering which languages don’t GC - maybe we can c...
New
PragmaticBookshelf
Use WebRTC to build web applications that stream media and data in real time directly from one user to another, all in the browser. ...
New
AstonJ
We’ve talked about his book briefly here but it is quickly becoming obsolete - so he’s decided to create a series of 7 podcasts, the firs...
New
AstonJ
Was just curious to see if any were around, found this one: I got 51/100: Not sure if it was meant to buy I am sure at times the b...
New
New
PragmaticBookshelf
Develop, deploy, and debug BEAM applications using BEAMOps: a new paradigm that focuses on scalability, fault tolerance, and owning each ...
New
NewsBot
Node.js v22.14.0 has been released. Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New

Sub Categories: