Room Debug DAOs in Android: Streamlining Your Workflow

Room Debug DAOs in Android: Streamlining Your Workflow

This blog post explains how to create Room DAOs specifically for your Android debug build. These debug-only DAOs enable you to implement developer-centric features without affecting your production app.

Keeping your codebase clean is essential for long-term maintainability. Debug-only DAOs help achieve this by isolating developer tools from user-facing features.

Consider an app that caches and displays items. A “delete all items” function, while helpful for developers, shouldn’t be exposed to users. A separate debug DAO provides this functionality without cluttering your production code or creating confusion about the app’s core features.

So let’s get to it! We use Room for our database and this is not a room tutorial, so some previously familiarity will be needed. šŸ™‚

When you use the Room persistence library to store your app’s data, you interact with the stored data by defining data access objects, or DAOs. Each DAO includes methods that offer abstract access to your app’s database. At compile time, Room automatically generates implementations of the DAOs that you define.

https://developer.android.com/training/data-storage/room/accessing-data

First things first, we create a typical Room database (all code available here):

@Database(entities = [Item::class], version = 1, exportSchema = false)
abstract class ShopDatabase : RoomDatabase() {
    abstract fun itemDao(): ItemDao

    companion object {
        @Volatile
        private var Instance: ShopDatabase? = null

        /**
         * https://developer.android.com/codelabs/basic-android-kotlin-compose-persisting-data-room#6
         */
        fun getDatabase(context: Context): ShopDatabase {
            return Instance ?: synchronized(this) {
                Room.databaseBuilder(context, ShopDatabase::class.java, "shop_database")
                    .fallbackToDestructiveMigration()
            }
                .build()
                .also { Instance = it }
        }
    }
}

With a DAO that allows insertions and streaming all values:

@Dao
interface ItemDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(item: Item)

    @Query("SELECT * from items")
    fun streamAll(): Flow<List<Item>>
}

Now the magic. We’ll be creating a single interface with two different signatures depending on the sourceset. Adding a DAO that can delete all items for debug apps, and an empty extension interface for your production apps (i.e. no extra behaviour).

/**
 * DAO extensions available in the debug source set only (matching interface in the release source set)
 */
interface DaoExtensions {
    fun debugItemDao(): DebugItemDao
}

@Dao
interface DebugItemDao {
    @Query("DELETE FROM items")
    fun deleteAll()
}

/**
 * DAO extensions available in the release source set only (matching interface in the debug source set)
 */
interface DaoExtensions {
    // Nothing for release builds
}

Notice what we have DaoExtensions in the debug sourceset and the release sourceset:

To hook up this new Extension interface you simply add it to your abstract database definition:

@Database(entities = [Item::class], version = 1, exportSchema = false)
abstract class ShopDatabase : RoomDatabase(), DaoExtensions {

And that’s it! This setup means that when the code is built and code generation kicks in, (which is how Room creates the actual database code) the debug app will be able to access a deleteAll method on your database, (Room will generate a DebugItemDao) the production (release) app will not have access to this code.

How you would use a feature like this, is to have a “Debug Screen” for your application. A debug screen in an Android app is a hidden or special screen that developers use to get more information about the app’s current state and to test different functionalities. It’s like a secret menu with tools to help you find and fix problems. The example code to go with the blog (here) has an example of doing just that here.

Congrats! You have added database manipulation to your suite of in app debug tools!

Thanks for listening.

All code is availableĀ on GitHub here.

Any questions, you can find me on:

BlueSky @Blundell_apps (or Threads, or X, ?)

Special shoutout to Danny Santiago for coming up with the extension idea.


Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *