suspend w bloku runInTransaction

Sep 01 2020

Mam błąd kompilacji przy użyciu poniższego kodu:

Funkcje zawieszenia można wywołać tylko w ramach korpusu

Czy ktoś może mi wyjaśnić, dlaczego? Co muszę zrobić, aby działało (bez korzystania z @Transactionadnotacji)?

override suspend fun replaceAccounts(newAccounts: List<Account>) {
    database.runInTransaction {
        database.accountDao().deleteAllAccounts() // I have the error on this line
        database.accountDao().insertAccounts(newAccounts) // Here too
    }
}

@Dao
abstract class AccountDao : BaseDao<AccountEntity> {

    @Query("DELETE FROM Account")
    abstract suspend fun deleteAllAccounts()

}

Z góry dziękuje za twoją pomoc

Odpowiedzi

9 IR42 Sep 01 2020 at 02:58

W przypadku suspendfunkcji użyj withTransactionzamiastrunInTransaction

hightech Sep 01 2020 at 03:02

Operacje związane z operacjami we / wy i inne długotrwałe operacje (takie jak wywołania bazy danych lub API) nie mogą być uruchamiane bezpośrednio w głównym wątku (co w przeciwnym razie mogłoby spowodować, że program przestanie odpowiadać). Korekty są jak lekkie wątki, które działają asynchronicznie w obrębie wątku.

Proponuję przeczytać przewodnik Coroutines pod adresem https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html

Aby odpowiedzieć na swoje pytanie, musisz ustawić zakres roboczy i wątek dyspozytora, na którym będzie działać twój program. Najprostszy to coś takiego:

GlobalScope.launch(Dispatchers.IO) {
    replaceAccounts(newAccounts)
}

który uruchomiłby twój coroutine w GlobalScope („cykl życia” coroutine jest powiązany z cyklem życia całej aplikacji), w wątku IO (wątku poza głównym wątkiem, który obsługuje zadania IO).

EDYCJA Podoba mi się odpowiedź @ IR42. Aby to wykorzystać, użycie withTransactionw tym przypadku pozwala Roomowi obsługiwać wątek, w którym wykonywane są operacje bazy danych, i pomaga ograniczyć współbieżność do bazy danych.

GlobalScope.launch(Dispatchers.Main) {
    replaceAccounts(newAccounts)
}

override suspend fun replaceAccounts(newAccounts: List<Account>) {
    database.withTransaction {
        database.accountDao().deleteAllAccounts() // I have the error on this line
        database.accountDao().insertAccounts(newAccounts) // Here too
    }
}

Zobacz więcej informacji na temat tego artykułu autorstwa jednego z pokojów: https://medium.com/androiddevelopers/threading-models-in-coroutines-and-android-sqlite-api-6cab11f7eb90