问题描述
我知道这是一个复杂的问题,如果不发布几百行代码就无法得到明确的答案,这就是为什么我要通过一般的想法和指示寻求帮助。
我有一个房间 @Query
返回我在 RxJava 线程 Flowable<List<...>>
上订阅的 RxJava3 Schedulers.io()
,并从 RxJava 线程 {{ 上的活动范围 viewmodel
观察1}}。然后将数据作为 AndroidSchedulers.mainThread()
存储在我的 viewmodel 中,在处理 Android 组件的生命周期方面,它比 RxJava 表现得更好。
这个想法是有一个干净和即时的数据更新模式,不必在每个 Activity 或片段生命周期事件(例如 LiveData
和 onPaused
)上分别处理处置和重新订阅,并且即使我的活动被隐藏,也会在后台更新,以避免在返回我的活动时出现可怕的刷新延迟。我对这种设计模式感到非常惊讶。我仍然是,但我开始怀疑了。
当开始另一个具有相同设计模式的 Activity 时,我确实更改了一个值并立即从另一个 onResumed
获取更新的 List<...>
。不同的viewmodel
,不同的Activity
,相同的设计,相同的数据库表。返回第一个 viewmodel
时,我发现新数据永远不会更新:即使数据集已更改,Room 也没有发出任何更新。我必须重新处理和订阅才能看到新数据。
所以我的问题是:关于我的问题的根源可能在哪里的任何指示?!这个设计模式的核心是不是有什么烂地方?我对所有这些东西应该一起工作的误解?由于某些线程问题,这只是我的错误吗?还是我应该为 Room 填写错误报告?
我尝试从我的第一个 Activity
的 viewmodel
观察另一个非 Room RxJava3 observable,并且在其数据集更新时它确实会得到更新。
顺便说一下,我也使用 Hilt 将所有内容注入为 Activity
。
感谢您的时间:-)
解决方法
经过一周的头痛,我终于偶然发现了一个解决方案,它恰好是干净优雅的。
问题是 RxJava,我刚刚了解到,它不应该无缝地处理对同一个 Observable
的多个订阅。解决方案应该是使用 publish()
、connect()
、refcount()
运算符,或者更好地使用快捷方式 share()
。我尝试了所有我能想到的方法,但都没有成功(它实际上使情况变得更糟)。我还尝试从我的存储库 subscribe()
到房间 Flowable
并通过 BehaviorSubject
代理它。
Room 的文档中有这个奇怪的 org.reactivestreams.Publisher
,它的附加值我不知道,它的起源甚至不是我熟悉的 io.reactivex.rxjava3
。事实证明,这就是解决方案。 编辑:事实证明 Publisher
是一个 Flowable
碰巧实现的接口。
build.gradle
implementation 'android.arch.lifecycle:reactivestreams:+'
Dao.java
@Query("...")
Flowable<List<...>> getFlowable();
ViewModel.java
public liveData;
@Inject
public ViewModel(@NonNull RoomDatabase roomDatabase) {
liveData = LiveDataReactiveStreams.fromPublisher(roomDatabase.dao().getFlowable());
}
这似乎太容易了,但据我所知,它似乎完美这样更好。
编辑:
事实证明,这个问题的根源比我想象的要严重一些。我假设我的依赖注入 @InstallIn(SingletonComponent.class)
中的 @Module
就足够了,但显然每个 @Singleton
方法上还需要一个 @Provides
注释。
@Module
@InstallIn(SingletonComponent.class)
public abstract class DependencyInjection
{
@Provides
@NonNull
@Singleton // do not omit this
public static DataDao provideDataDao(@NonNull RoomDatabase roomDatabase) {
return roomDatabase.dataDao();
}
@Provides
@NonNull
@Singleton // do not omit this
public static RoomDatabase provideRoomDatabase(@ApplicationContext Context applicationContext) {
return
BuildConfig.DEBUG ?
Room.databaseBuilder(applicationContext,RoomDatabase.class,"playground.db").fallbackToDestructiveMigration().build() :
Room.databaseBuilder(applicationContext,"playground.db").build() ;
}
}