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/Activity
和SyncAdapter
中使用相同的productDao
对象,以便在插入新产品时触发LiveData,否则将不会被触发。 所以,要获得相同的productDao
我必须得到相同的(即单身) AppDatabase
。
我知道这可以使用ContentProvider
来实现,这是在插入新数据时自动触发的。 但我真的想尝试新的android架构组件。 或者,也许使用ContentProvider
是唯一正确的方法来实现这个用例?
当你想在不同的Threads
之间进行简单的通信时,你需要处于同一个进程中。
在AndroidManifest.xml
您可以指定一个名为android:process=":processName"
的属性,这些属性可用于Activities , Services (与SyncAdapter相关), Content Providers和Broadcast 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) }