SyncAdapter中的Singleton Room数据库触发LiveData

我努力在我的SyncAdapter使用Room作为单例。 我使用Kotlin。

我的房间课

 @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) 

而我的问题是,我总是在我的活动和SyncAdapter获得两个不同的AppDatabase实例。 虽然活动AppDatabase对象确实是单例.AppDatabase_Impl@3c9ff34d ,并且对于每个onPerformSync(), AppDatabase也是单例.AppDatabase_Impl@7d7718d 。 但正如你所看到的,他们是两个不同的对象。 任何人都可以解释我在这里想念的吗?

另一方面,也许我在想要实现的概念上是错误的。 那么任何意见将不胜感激。

重点在于当通过SynAdapter从远程服务器插入新数据时,使用LiveData更新UI组件。 在这种情况下,我必须在ViewModel/ActivitySyncAdapter中使用相同的productDao对象,以便在插入新产品时触发LiveData,否则将不会被触发。 所以,要获得相同的productDao我必须得到相同的(即单身) AppDatabase

我知道这可以使用ContentProvider来实现,这是在插入新数据时自动触发的。 但我真的想尝试新的android架构组件。 或者,也许使用ContentProvider是唯一正确的方法来实现这个用例?

当你想在不同的Threads之间进行简单的通信时,你需要处于同一个进程中。

AndroidManifest.xml您可以指定一个名为android:process=":processName"的属性,这些属性可用于ActivitiesServices (与SyncAdapter相关), Content ProvidersBroadcast Receivers ,可以帮助您超出Heap(内存)为单一过程。

这些是总结的PRO / CONS:

多进程PRO:你有更多的内存来运行你的应用程序,如果一个进程崩溃它不会崩溃其他的。

多进程缺点:让进程相互通信要困难得多(但也不是不可能),但显然你不能共享它们之间的状态(在你的情况下,状态是单例)

为了深刻理解,你应该阅读这篇文章和这个好的答案

我的建议是 :如果你的应用程序不是那么复杂,你没有记忆问题,我建议你从单一的过程方法开始。 而如果你想分离从应用程序更新你的数据的SyncAdapter,或者在开发的某个时候,你发现与单进程相关的瓶颈或崩溃,你应该切换到多进程,移除直接的LiveData,并使用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() } 

来自活动:

 @Inject lateinit var mRoomDatabase: AppDatabase override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) (application as MyApplication).component.inject(this) }