SyncAdapter中的Singleton Room数据库触发LiveData
Singleton Room database in SyncAdapter to trigger LiveData
我很难在我的 SyncAdapter
中使用 Room
作为单例。我用 Kotlin。
我的房间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()
}
}
我像这样检索数据库实例
val db = AppDatabase.getInstance(applicationContext)
我的问题是我总是在我的活动中得到两个不同的 AppDatabase
实例和 SyncAdapter
。尽管在活动中 AppDatabase
对象确实是单例 .AppDatabase_Impl@3c9ff34d
,并且对于每个 onPerformSync(),AppDatabase
也是单例 .AppDatabase_Impl@7d7718d
。
但正如您所见,它们是两个不同的对象。
谁能解释一下我在这里想念的东西?
另一方面,也许我在尝试实现的目标方面在概念上是错误的。那么任何建议将不胜感激。
重点是在通过 SynAdapter
从远程服务器插入新数据时使用 LiveData
更新 UI 组件。在这种情况下,我必须在 ViewModel/Activity
和 SyncAdapter
中使用相同的 productDao
对象,以便在插入新产品时触发 LiveData,否则它不会被触发。
因此,要获得相同的 productDao
我必须获得相同的(即单例)AppDatabase
.
我知道这可以使用 ContentProvider
来实现,它会在插入新数据时自动触发。但我真的很想尝试新的 android 架构组件。
或者也许使用 ContentProvider
是实现此用例的唯一正确方法?
使用 dagger2:
class MyApplication : Application(){
val component: AppComponent by lazy {
DaggerAppComponent.builder().appModule(AppModule(this)).build()
}
@Inject
lateinit var database : AppDatabase
override fun onCreate() {
super.onCreate()
component.inject(this)
}
}
@Singleton
@Component(modules = arrayOf(
AppModule::class
))
interface AppComponent {
fun inject(app: MyApplication)
}
@Module
class AppModule constructor(private val context: Context) {
@Provides
@Singleton
fun providesDatabase() = Room.databaseBuilder(context, AppDatabase::class.java, "mydb.db").build()
}
来自 activity :
@Inject lateinit var mRoomDatabase: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(application as MyApplication).component.inject(this)
}
当你想在不同的 Threads
之间轻松交流时,你需要在同一个进程中。
在 AndroidManifest.xml
中,您可以指定一个名为 android:process=":processName"
的属性,可用于 Activities、Services(与 SyncAdapters 相关),Content Providers 和 Broadcast Receivers,这可以帮助您超过单个进程的堆(内存)默认限制。
这些是总结 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)
要深入了解,您应该阅读this article and this good answer
我的建议:如果您的应用程序不是那么复杂并且您没有内存问题,我建议您从单进程方法开始。如果你想从应用程序中解耦更新你的数据的 SyncAdapter,或者在开发的某个时候你发现与单进程相关的瓶颈或崩溃,你可以切换到多进程,删除直接 LiveData 并使用 ContentProvider 来传达数据变化。
我很难在我的 SyncAdapter
中使用 Room
作为单例。我用 Kotlin。
我的房间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()
}
}
我像这样检索数据库实例
val db = AppDatabase.getInstance(applicationContext)
我的问题是我总是在我的活动中得到两个不同的 AppDatabase
实例和 SyncAdapter
。尽管在活动中 AppDatabase
对象确实是单例 .AppDatabase_Impl@3c9ff34d
,并且对于每个 onPerformSync(),AppDatabase
也是单例 .AppDatabase_Impl@7d7718d
。
但正如您所见,它们是两个不同的对象。
谁能解释一下我在这里想念的东西?
另一方面,也许我在尝试实现的目标方面在概念上是错误的。那么任何建议将不胜感激。
重点是在通过 SynAdapter
从远程服务器插入新数据时使用 LiveData
更新 UI 组件。在这种情况下,我必须在 ViewModel/Activity
和 SyncAdapter
中使用相同的 productDao
对象,以便在插入新产品时触发 LiveData,否则它不会被触发。
因此,要获得相同的 productDao
我必须获得相同的(即单例)AppDatabase
.
我知道这可以使用 ContentProvider
来实现,它会在插入新数据时自动触发。但我真的很想尝试新的 android 架构组件。
或者也许使用 ContentProvider
是实现此用例的唯一正确方法?
使用 dagger2:
class MyApplication : Application(){
val component: AppComponent by lazy {
DaggerAppComponent.builder().appModule(AppModule(this)).build()
}
@Inject
lateinit var database : AppDatabase
override fun onCreate() {
super.onCreate()
component.inject(this)
}
}
@Singleton
@Component(modules = arrayOf(
AppModule::class
))
interface AppComponent {
fun inject(app: MyApplication)
}
@Module
class AppModule constructor(private val context: Context) {
@Provides
@Singleton
fun providesDatabase() = Room.databaseBuilder(context, AppDatabase::class.java, "mydb.db").build()
}
来自 activity :
@Inject lateinit var mRoomDatabase: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(application as MyApplication).component.inject(this)
}
当你想在不同的 Threads
之间轻松交流时,你需要在同一个进程中。
在 AndroidManifest.xml
中,您可以指定一个名为 android:process=":processName"
的属性,可用于 Activities、Services(与 SyncAdapters 相关),Content Providers 和 Broadcast Receivers,这可以帮助您超过单个进程的堆(内存)默认限制。
这些是总结 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)
要深入了解,您应该阅读this article and this good answer
我的建议:如果您的应用程序不是那么复杂并且您没有内存问题,我建议您从单进程方法开始。如果你想从应用程序中解耦更新你的数据的 SyncAdapter,或者在开发的某个时候你发现与单进程相关的瓶颈或崩溃,你可以切换到多进程,删除直接 LiveData 并使用 ContentProvider 来传达数据变化。