Заставить приостановленную функцию работать в одном потоке для отображения объектов Realm в фоновом режиме - PullRequest
2 голосов
/ 27 мая 2019

Допустим, мне периодически (каждые 3 секунды) нужно читать список из нескольких RealmObject с, и я хочу сопоставить эти объекты с простыми объектами данных, которые будут использоваться для заполнения содержимого списков.

Для тех, кто интересуется, есть три причины для этого:

  • большая сложность вычисления значений и поведения (видимости, т. Е.) Представлений в ViewHolder с в моем случае
  • Я хочу использовать ListAdapter, который должен предоставить DiffUtilCallback, который будет выполняться в каком-то другом потоке, отличном от пользовательского интерфейса, поэтому выполнение необходимых вычислений в его методах невозможно, поскольку они будут использоваться из потока, в котором они находятсяне создан.
  • удаление зависимости уровня представления от Realm

Я не могу просто использовать сопрограммы основным способом, которые переходят из одного доступного потока при его выполнении в другой, так как я буду (и я сделал)в конечном итоге получите «Область уже закрыта» * исключение 1018 *.

Единственное решение, которое я придумаю, - это использование диспетчера, использующего только один поток 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, и, в конце концов, у меня будет один поток для сопоставления всего приложения в фоновом режиме, и моя «основная» viewModel вызовет в 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 аннотацию, так что это означает, что она будетудален в ближайшее время.

Мой вопрос: может ли кто-нибудь предложить другое решение, кроме использования этого устаревшего Диспетчера?

1 Ответ

2 голосов
/ 28 мая 2019

Очень легко создать свой собственный однопоточный диспетчер из Java-исполнителя:

val singleThreadContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
...