I'm struggling to use Room
as singleton in my SyncAdapter
. I use Kotlin.
My room class
@Database(entities = [(Product::class)], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun productDao(): ProductDao
companion object {
@Volatile private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context) : AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context.applicationContext)
.also {INSTANCE = it}
}
private fun buildDatabase(context: Context) =
Room
.databaseBuilder(context.applicationContext,
AppDatabase::class.java, "database.db")
.allowMainThreadQueries()
.build()
}
}
I retrieve database instance like this
val db = AppDatabase.getInstance(applicationContext)
And my issue is that I always get two different instances of AppDatabase
in my activities and SyncAdapter
. Though among activities AppDatabase
object is indeed singleton .AppDatabase_Impl@3c9ff34d
, and for each onPerformSync() the AppDatabase
is singleton too .AppDatabase_Impl@7d7718d
.
But as you can see they are two different objects.
Can any one explain what I miss here?
On the other hand maybe I'm conceptually wrong in what I'm trying to achieve. Then any advice would be appreciated.
The point is to use LiveData
to update UI components when new data is inserted from remote server via SynAdapter
. In this case I have to use the same productDao
object in ViewModel/Activity
and in SyncAdapter
in order to trigger LiveData on inserting new products, otherwise it won't be triggered.
So, to obtain the same productDao
I must get the same(i.e. singleton) AppDatabase
.
I know that this can be implemented using a ContentProvider
, that is triggered automatically on inserting new data. But I really want to try new android architecture components.
Or maybe using ContentProvider
is the only correct way to implement this use-case?
When you want an easy communication between different Threads
you need to be in the same process.
In the AndroidManifest.xml
you can specify an attribute called android:process=":processName"
usable on Activities, Services(which relates to SyncAdapters), Content Providers and Broadcast Receivers, which can help you exceed the default limits of Heap (memory) for single process.
Those are the summarized PRO/CONS:
Multi-process PRO: You have more memory to run your app and if a process crashes it doesn't crash the other ones.
Multi-process CONS: It's a lot more difficult (but not impossible) to let the processes communicate with each other but obviously you can't share the state between them (in your case the state is the singleton)
For a deep understanding, you should read this article and this good answer
My suggestion: If your app is not so complex and you don't have memory problems I'll suggest you start with the single process approach. While if you want to decouple the SyncAdapter which update your data from the app, or at some point in the development you find bottlenecks or crashes related to the single-process, you could switch to multi-process, remove direct LiveData and use ContentProvider to communicate data changes.