Скажем, мне периодически (каждые 3 секунды) нужно читать список некоторых RealmObject
, и я хочу сопоставить эти объекты с простыми объектами данных, которые будут использоваться для заполнения содержимого списков.
Для тех, кто задается вопросом, на это есть три причины:
- большая сложность вычисления значений и поведения (видимости, т. е.) представлений в
ViewHolder
s в моем случае - Я хочу использовать
ListAdapter
, который должен иметьDiffUtilCallback
, который будет выполняться в каком-то другом потоке, кроме пользовательского интерфейса, поэтому выполнение необходимых вычислений в его методах невозможно, потому что они будут использоваться из потока, в котором они не созданы. - удаление зависимости слоя просмотра от 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() }
}
}
Этот класс предоставляется как Singleton через Dagger, и в конечном итоге у меня будет один поток для отображения всего приложения в фоновом режиме, и моя «основная» модель просмотра будет вызывать свой onClosed
метод close()
этого класса.
Вот как я его использую:
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
, значит, она скоро будет удалена.
Мой вопрос: может ли кто-нибудь предложить другое решение, кроме использования этого устаревшего Диспетчера?