suspend, méthode dans le bloc runInTransaction

Sep 01 2020

J'ai une erreur de compilation en utilisant le code ci-dessous:

Les fonctions de suspension ne peuvent être appelées que dans le corps de la coroutine

Quelqu'un peut-il m'expliquer pourquoi? Que dois-je faire pour que cela fonctionne (sans utiliser l' @Transactionannotation)?

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()

}

Merci d'avance pour votre aide

Réponses

9 IR42 Sep 01 2020 at 02:58

Pour les suspendfonctions, utilisez withTransactionau lieu derunInTransaction

hightech Sep 01 2020 at 03:02

Les opérations liées aux E / S et autres opérations de longue durée (telles que les appels de base de données ou d'API) ne peuvent pas être exécutées directement dans le thread principal (ce qui pourrait sinon empêcher votre programme de répondre). Les coroutines sont comme des threads légers qui s'exécutent, de manière asynchrone, dans un thread.

Je suggère de lire le guide Coroutines à https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html

Pour répondre à votre question, vous devez configurer une portée de coroutine et un thread de distribution sur lequel votre coroutine doit s'exécuter. Le plus simple est quelque chose comme:

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

qui exécuterait votre coroutine dans le GlobalScope (le «cycle de vie» de la coroutine est lié au cycle de vie de l'application entière), sur le thread IO (un thread en dehors du thread principal qui gère les tâches d'E / S).

EDIT J'aime la réponse de @ IR42. Pour s'appuyer sur cela, l'utilisation de withTransactiondans ce cas permet à Room de gérer le thread dans lequel les opérations de base de données sont effectuées et aide à limiter la concurrence d'accès à la base de données.

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
    }
}

Voir plus d'informations sur cet article par l'un des membres de Room: https://medium.com/androiddevelopers/threading-models-in-coroutines-and-android-sqlite-api-6cab11f7eb90