Я не использую Realm, так что я могу ошибаться, что-то здесь, но, просматривая их вводное руководство, там говорится об инициализации Realm в onCreate
(Realm.init(this)
). Это означает, что он ожидает взаимодействия с основным потоком пользовательского интерфейса. Это означает, что вы должны использовать только Dispatchers.Main
, и, пока вы запускаете свои сопрограммы из основной области, такой как lifecycleScope
или viewModelScope
, вам не нужно указывать диспетчеров или вообще использовать withContext
. Методы Realm, которые имеют аргумент обратного вызова, - это то, где он будет делать что-то в фоновом потоке, но вы никогда не должны взаимодействовать с ним в фоновом потоке.
В вашем примере выше, похоже, что вы просто регистрация наблюдателей в вашей функции invoke
. Регистрация наблюдателей не является блокирующим вызовом, поэтому вам не следует использовать для нее функцию приостановки или пытаться сделать это в фоновом режиме с помощью withContext()
.
Область, в которой сопрограммы имеют смысл, - это когда есть некоторые блокирующие действия выполняются в фоновом режиме. Из руководства видно, что Realm предлагает асинхронные транзакции. Похоже, что Realm пока не поддерживает сопрограммы, но вы можете преобразовать методы asyn c в функции приостановки следующим образом:
/** @return `null` on success or a Throwable on failure. */
suspend fun Realm.executeTransactionSuspending(transaction: Realm.Transaction): Throwable? =
suspendCoroutine { continuation ->
executeTransactionAsync(
transaction,
{ continuation.resume(null) },
{ throwable -> continuation.resume(throwable) }
)
}
Затем вы можете запускать сопрограммы из основного потока, используя viewModelScope
( или lifecycleScope
, если вы находитесь в Деятельности / Фрагменте):
fun doSomeTransaction() = viewModelScope.launch {
val error = realm.executeTransactionSuspending { bgRealm ->
val user = bgRealm.createObject<User>()
user.name = "John"
user.email = "john@corporation.com"
}
if (error != null) {
// handle error
return@launch
}
// Success. Can do subsequent action like updating live data.
// If using this directly from an Activity/Fragment (not good MVVM), you could safely update UI
// here because lifecycleScope will have cancelled it before it gets to this step if the
// Activity/Fragment is already gone.
}
Опять же, я не использую Царство. Ничто из вышеперечисленного не проверено. Вы можете искать информацию о превращении обратных вызовов в Kotlin сопрограмм, если вам нужна помощь, чтобы заставить его работать. Вы также можете использовать coroutine.resumeWithException(throwable)
, если хотите обернуть ваши звонки в try/catch
. Я подумал, что имеет смысл возвращать throwable, поскольку Realm делает необязательным даже получение обратного вызова при сбое.