Room database reset after app close and reopen

  Kiến thức lập trình

I created a Compose app with a room database and flows, which is loading data from an assets database. Then I add favorites and more stuff. It works and stores favorites until I close the app and reopen it. Then, all favorites are lost and the database seems to be the same as the assets database. Any idea about what I’m doing wrong?

the database:

@Database(entities = [Airport::class, Favorite::class], version = 1)
abstract class FlightsDatabase : RoomDatabase() {
    abstract fun flightsDao(): FlightsDao

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

        fun getDatabase(context: Context): FlightsDatabase {
            return Instance ?: synchronized(this) {
                Room.databaseBuilder(
                    context,
                    FlightsDatabase::class.java,
                    "app_database"
                )
                    .createFromAsset("database/flight_search.db")
                    .fallbackToDestructiveMigration()
                    .build()
                    .also { Instance = it}
            }
        }
    }
}

the repository initialization:

class DefaultAppContainer(private val context: Context) : AppContainer {
    override val flightRepository: FlightsRepository by lazy {
        OfflineFlightsRepository(FlightsDatabase.getDatabase(context).flightsDao())
    }
    override val userPreferencesRepository = UserPreferencesRepository(context.dataStore)
}

the repository:

interface FlightsRepository {
    fun getAllAirports(): Flow<List<Airport>>
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>
    fun getFavorites(): Flow<List<Favorite>>
    suspend fun insertFavorite(favorite: Favorite)
}

class OfflineFlightsRepository(private val flightsDao: FlightsDao) : FlightsRepository {
    override fun getAllAirports(): Flow<List<Airport>> {
        return flightsDao.getAllAirports()
    }

    override fun getAirportsByIatOrName(text: String): Flow<List<Airport>> {
        return flightsDao.getAirportsByIatOrName(text)
    }

    override fun getAllDifferentAirports(id: Int): Flow<List<Airport>> {
        return flightsDao.getAllDifferentAirports(id)
    }

    override fun getFavorites(): Flow<List<Favorite>> {
        return flightsDao.getFavorites()
    }

    override suspend fun insertFavorite(favorite: Favorite) {
        val foundFavorite = flightsDao.getFavoriteByIATAS(favorite.departureCode, favorite.destinationCode)

        if (foundFavorite != null && foundFavorite.first() != null) {
            val favorite = foundFavorite.first()
            flightsDao.deleteFavorite(favorite)
        } else {
            flightsDao.insertFavorite(favorite)
        }
    }
}

the dao:

@Dao
interface FlightsDao {
    @Query("SELECT * FROM airport ORDER BY passengers DESC")
    fun getAllAirports(): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE iata_code LIKE '%'||:text||'%' OR name LIKE '%'||:text||'%' ORDER BY passengers DESC")
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE id NOT LIKE :id ORDER BY passengers DESC")
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>

    @Query("SELECT * FROM favorite")
    fun getFavorites(): Flow<List<Favorite>>

    @Query("SELECT EXISTS(SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode)")
    suspend fun checkIfFavoriteExists(departureCode: String, destinationCode: String): Boolean

    @Query("SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode")
    fun getFavoriteByIATAS(departureCode: String, destinationCode: String): Flow<Favorite>?

    @Insert
    suspend fun insertFavorite(favorite: Favorite)

    @Delete
    suspend fun deleteFavorite(favorite: Favorite)
}

Room database reset after app close and reopen

I created a Compose app with a room database and flows, which is loading data from an assets database. Then I add favorites and more stuff. It works and stores favorites until I close the app and reopen it. Then, all favorites are lost and the database seems to be the same as the assets database. Any idea about what I’m doing wrong?

the database:

@Database(entities = [Airport::class, Favorite::class], version = 1)
abstract class FlightsDatabase : RoomDatabase() {
    abstract fun flightsDao(): FlightsDao

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

        fun getDatabase(context: Context): FlightsDatabase {
            return Instance ?: synchronized(this) {
                Room.databaseBuilder(
                    context,
                    FlightsDatabase::class.java,
                    "app_database"
                )
                    .createFromAsset("database/flight_search.db")
                    .fallbackToDestructiveMigration()
                    .build()
                    .also { Instance = it}
            }
        }
    }
}

the repository initialization:

class DefaultAppContainer(private val context: Context) : AppContainer {
    override val flightRepository: FlightsRepository by lazy {
        OfflineFlightsRepository(FlightsDatabase.getDatabase(context).flightsDao())
    }
    override val userPreferencesRepository = UserPreferencesRepository(context.dataStore)
}

the repository:

interface FlightsRepository {
    fun getAllAirports(): Flow<List<Airport>>
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>
    fun getFavorites(): Flow<List<Favorite>>
    suspend fun insertFavorite(favorite: Favorite)
}

class OfflineFlightsRepository(private val flightsDao: FlightsDao) : FlightsRepository {
    override fun getAllAirports(): Flow<List<Airport>> {
        return flightsDao.getAllAirports()
    }

    override fun getAirportsByIatOrName(text: String): Flow<List<Airport>> {
        return flightsDao.getAirportsByIatOrName(text)
    }

    override fun getAllDifferentAirports(id: Int): Flow<List<Airport>> {
        return flightsDao.getAllDifferentAirports(id)
    }

    override fun getFavorites(): Flow<List<Favorite>> {
        return flightsDao.getFavorites()
    }

    override suspend fun insertFavorite(favorite: Favorite) {
        val foundFavorite = flightsDao.getFavoriteByIATAS(favorite.departureCode, favorite.destinationCode)

        if (foundFavorite != null && foundFavorite.first() != null) {
            val favorite = foundFavorite.first()
            flightsDao.deleteFavorite(favorite)
        } else {
            flightsDao.insertFavorite(favorite)
        }
    }
}

the dao:

@Dao
interface FlightsDao {
    @Query("SELECT * FROM airport ORDER BY passengers DESC")
    fun getAllAirports(): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE iata_code LIKE '%'||:text||'%' OR name LIKE '%'||:text||'%' ORDER BY passengers DESC")
    fun getAirportsByIatOrName(text: String): Flow<List<Airport>>

    @Query("SELECT * FROM airport WHERE id NOT LIKE :id ORDER BY passengers DESC")
    fun getAllDifferentAirports(id: Int): Flow<List<Airport>>

    @Query("SELECT * FROM favorite")
    fun getFavorites(): Flow<List<Favorite>>

    @Query("SELECT EXISTS(SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode)")
    suspend fun checkIfFavoriteExists(departureCode: String, destinationCode: String): Boolean

    @Query("SELECT * FROM favorite WHERE departure_code = :departureCode AND destination_code = :destinationCode")
    fun getFavoriteByIATAS(departureCode: String, destinationCode: String): Flow<Favorite>?

    @Insert
    suspend fun insertFavorite(favorite: Favorite)

    @Delete
    suspend fun deleteFavorite(favorite: Favorite)
}

LEAVE A COMMENT