I am working on refactoring an android application (I'm not the original author) which uses a pre-created sqlite database file received from the backend. It is done like this because my client's use case needs a local database in which one of the tables can have 1 million rows in some cases. It is a stock-taking app for a rugged device which needs to work offline which means that the device needs to store the entire database of all the various products that can be found for the given warehouse so that the workers can see a product's information after scanning it's barcode. Every day at the start of the work on a new project, the pre-created database gets acquired from the backend and is used for the remainder of the project for the rest of the day.
I use Room for the database and also use Hilt. Normally everything works fine. The problem arises when/if the client uses a functionality in which the app can re-download the pre-created database from the backend which means that the entire database file Room uses gets rewritten. To avoid having references to a database that no longer exists, I close the database by calling my closeDatabase() method which then later gets recreated. The database class is the following (I shortened it and changed names due to NDA reasons):
@Database(
entities = [
ItemTable::class
],
exportSchema = false,
version = 1
)
abstract class ProjectDatabase : RoomDatabase() {
abstract fun roomItemDao(): ItemDao
companion object {
@Volatile
private var INSTANCE: ProjectDatabase? = null
fun getDatabase(): ProjectDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
MyApplication.appContext,
ProjectDatabase::class.java,
getDbNameWithPath()
).createFromAsset(getDbNameWithPath())
.build()
INSTANCE = instance
instance
}
}
fun closeDatabase() {
INSTANCE?.close()
INSTANCE = null
}
private fun getDbNameWithPath(): String {
return MyApplication.appContext.filesDir.toString()
File.separator Constants.PROJECT_DATABASE_NAME
}
}
}
I also use a Hilt module for the database like this:
@Module
@InstallIn(SingletonComponent::class)
class ProjectDatabaseModule {
@Provides
fun provideProjectDatabase(): ProjectDatabase {
return ProjectDatabase.getDatabase()
}
@Provides
fun provideItemDao(
projectDatabase: ProjectDatabase
): ItemDao {
return projectDatabase.roomItemDao()
}
}
My problem is that when I set the INSTANCE to null, then the next call to getDatabase() creates a new instance, but all the references previously created by Hilt for the various classes still reference the old instance.
If I don't call INSTANCE = null then the database doesn't get reopened. If I don't close the database, then Room goes insane due to having its entire underlying database completely changed. Previously I always called getDatabase().xyz which worked but was kinda ugly, thus I started to use Hilt for it.
Is there a solution for this via Hilt? I'm afraid I'll have to go back to my old solution. Even if I change my scope to something else, the already existing classes will use the old reference.
Basically what I wish for is a call to ProjectDatabase.getDatabase.roomItemDao() every time I call a method of ItemDao.
CodePudding user response:
I decided that the best solution in this case is to either ask the user to restart your app or do it programmatically according to your given use case. Thanks to @MikeT for his reassuring comment.