强制挂起的函数在一个线程上工作以在后台映射 Realm 对象
Forcing suspended function to work on one thread for mapping Realm objects in background
假设我定期(每 3 秒)需要读取一些 RealmObject
的列表,我想将这些对象映射到将用于填充列表内容的简单数据对象。
对于那些想知道的人,有以下三个原因:
- 在我的案例中
ViewHolder
中计算视图的值和行为(可见性,即)非常复杂
- 我想使用
ListAdapter
,它需要提供 DiffUtilCallback
,它将在 UI 以外的其他线程上执行,因此无法在其方法中进行所需的计算,因为它们将从未创建它们的线程中使用。
- 正在从 Realm 中删除视图层的依赖性
我不能简单地以基本方式使用协同程序,即从执行中的一个可用线程跳转到另一个线程,因为我将(而且我确实)最终收到 "Realm is already closed" 例外。
我想出的唯一解决方案是使用仅使用一个线程的调度程序 newSingleThreadContext("RealmSingleThreadContext")
例如:
class RealmSingleThreadContext {
val ctx = NewSingleThreadedContext("RealmSingleThreadContext")
lateinit var realm : Realm
init {
// opening Realm connection for thread "RealmSingleThreadContext"
GlobalScope.launch(ctx) { realm = Realm.getDefaultInstance() }
}
fun close() {
GlobalScope.launch(ctx) { if (!realm.isClosed()) realm.close() }
}
}
这个 class 通过 Dagger 作为单例提供,最终在最后,我将有一个线程在后台为整个应用程序做映射,我的 "main" viewModel 将调用它的 onClosed
方法 close()
这个 class 的方法。
我是这样使用的:
class HomeViewModel @Inject constructor(/* other */var realmSingleThreadContext: RealmSingleThreadContext) {
var topLiveEventsUI: MutableLiveData<List<EventPreviewUI>> = MutableLiveData(listOf())
fun useRealmInBckg() {
viewModeScope.launch(realmSingleThreadContext.ctx) {
topLiveEventsUI.postValue(eventsReadUseCase.getTopLiveEvents()
.map{ mapper.map(it) }
}
}
}
唯一的问题是 newSingleThreadContext(name: String)
函数有 @ObsoleteCoroutineApi
注释,这意味着它很快就会被删除。
我的问题是:除了使用这个过时的 Dispatcher 之外,还有谁能提出另一种解决方案吗?
从 Java 执行器创建自己的 single-threaded 调度器非常容易:
val singleThreadContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
假设我定期(每 3 秒)需要读取一些 RealmObject
的列表,我想将这些对象映射到将用于填充列表内容的简单数据对象。
对于那些想知道的人,有以下三个原因:
- 在我的案例中
ViewHolder
中计算视图的值和行为(可见性,即)非常复杂 - 我想使用
ListAdapter
,它需要提供DiffUtilCallback
,它将在 UI 以外的其他线程上执行,因此无法在其方法中进行所需的计算,因为它们将从未创建它们的线程中使用。 - 正在从 Realm 中删除视图层的依赖性
我不能简单地以基本方式使用协同程序,即从执行中的一个可用线程跳转到另一个线程,因为我将(而且我确实)最终收到 "Realm is already closed" 例外。
我想出的唯一解决方案是使用仅使用一个线程的调度程序 newSingleThreadContext("RealmSingleThreadContext")
例如:
class RealmSingleThreadContext {
val ctx = NewSingleThreadedContext("RealmSingleThreadContext")
lateinit var realm : Realm
init {
// opening Realm connection for thread "RealmSingleThreadContext"
GlobalScope.launch(ctx) { realm = Realm.getDefaultInstance() }
}
fun close() {
GlobalScope.launch(ctx) { if (!realm.isClosed()) realm.close() }
}
}
这个 class 通过 Dagger 作为单例提供,最终在最后,我将有一个线程在后台为整个应用程序做映射,我的 "main" viewModel 将调用它的 onClosed
方法 close()
这个 class 的方法。
我是这样使用的:
class HomeViewModel @Inject constructor(/* other */var realmSingleThreadContext: RealmSingleThreadContext) {
var topLiveEventsUI: MutableLiveData<List<EventPreviewUI>> = MutableLiveData(listOf())
fun useRealmInBckg() {
viewModeScope.launch(realmSingleThreadContext.ctx) {
topLiveEventsUI.postValue(eventsReadUseCase.getTopLiveEvents()
.map{ mapper.map(it) }
}
}
}
唯一的问题是 newSingleThreadContext(name: String)
函数有 @ObsoleteCoroutineApi
注释,这意味着它很快就会被删除。
我的问题是:除了使用这个过时的 Dispatcher 之外,还有谁能提出另一种解决方案吗?
从 Java 执行器创建自己的 single-threaded 调度器非常容易:
val singleThreadContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()