0
votes

La pièce Coroutine est exécutée dans le thread principal

Je joue avec Kotlin Flow, Coroutines et Room. J'essaie d'insérer des données dans ma base de données de salle à partir de mon référentiel.

Lors de l'insertion d'un seul élément, il n'y a pas de problème mais si j'essaie d'insérer une liste d'éléments, l'exécution s'interrompt et le message suivant est enregistré sur la console:

@Insert
suspend fun insertItems(items: List<Item>)

Je ne comprends pas pourquoi l'opération d'insertion est exécutée sur le thread principal car selon la documentation, une opération DAO suspendue devrait toujours être exécutée dans une Coroutine initiée en interne par Room (qui devrait finalement s'exécuter sur un thread d'arrière-plan). J'ai également essayé d'exécuter l'appel d'insertion dans une autre portée explicitement (withContext (Dispatchers.IO) {...}) mais il n'y a aucune différence.

Voici à quoi ressemble mon code:

VoirModèle:

suspend fun getItems(): Flow<DataState<List<Item>>> = flow {
    emit(DataState.Loading)
    try {
        val items = itemService.getAllItems()
        emit(DataState.Success(items))
        itemDao.insertItems(items) // The execution stops here
    } catch (e: Exception) {
        emit(DataState.Error(e))
    }
}

Dépôt:

fun setStateEvent(stateEvent: StateEvent) {
    viewModelScope.launch {
        when (stateEvent) {
            is StateEvent.GetItems -> {
                repository.getItems().onEach { dateState ->
                    _dataState.value = dateState
                }.launchIn(viewModelScope)
            }
        }
    }
}

DAO:

I/Choreographer: Skipped 47 frames!  The application may be doing too much work on its main thread.

J'ai également essayé de déboguer et de trouver la source du problème mais je n'ai pas eu de chance. Je serais heureux si quelqu'un pouvait me dire ce qui ne va pas.


0 commentaires

3 Réponses :


-1
votes

Vous pouvez simplement ajouter le Dispatchers.IO au lancement du CoroutineScope qui exécute le viewmodelScope

implementation "androidx.room:room-ktx:2.2.5"

Assurez-vous que vous avez la dépendance de room-ktx dans votre gradle, cela vous permettra d'utiliser les fonctions de suspension à l'intérieur de votre interface avec room

fun setStateEvent(stateEvent: StateEvent) {
    viewModelScope.launch(Dispatchers.IO) {
        when (stateEvent) {
            is StateEvent.GetItems -> {
                repository.getItems().collect {
                for(item in it) { _dataState.value = item }
               }
            }
        }
    }
}

Voir: https://developer.android.com/jetpack/androidx/releases/room#declaring_dependencies

Dans tous les cas, vous ne pourrez pas bénéficier de la suspension dans l'interface de votre salle.


3 commentaires

repository.getItems() n'est jamais appelé lors de l'utilisation de votre code suggéré. Cela peut être corrigé si .collect() est appelé après .onEach() . Néanmoins, l'erreur suivante se produit: java.lang.IllegalStateException: Cannot invoke setValue on a background thread . La dépendance est déjà ajoutée. Pourquoi ne pourrais-je pas bénéficier de la suspension?


À l'intérieur de collect faire le dataState.value, j'ai changé le code, jetez-y un œil


Même erreur. _dataState est de type MutableLiveData et la méthode setValue doit être appelée sur le thread principal. EDIT: Vu votre modification en ce moment, je vais regarder votre code, merci! EDIT2: Cela ne fera aucune différence car il serait toujours appelé sur un thread IO et setValue doit être appelé depuis le thread principal.



1
votes

D'après ce que je vois, il n'y a pas de problème ici. Les messages du chorégraphe peuvent être trompeurs , ils n'ont peut-être rien à voir avec le fil de discussion principal. Je vois souvent cela lors du débogage, probablement en raison de la surcharge du débogueur. L'inflation de mises en page lourdes peut également en être la cause.

De plus, vous n'avez pas besoin de launchIn(viewModelScope) car le flux est déjà collecté dans cette portée. Utilisez simplement collect() . Et contrairement à ce que les autres réponses peuvent suggérer, vous avez raison de dire que la salle change automatiquement de thread lors de l'utilisation des méthodes de suspend DAO.


1 commentaires

Mais le message n'apparaît que lorsque la fonction insertItems est appelée. De plus , je suis sûr que l'exécution est en quelque sorte interrompue parce que les éléments ne sont pas se persistaient et aussi, si je passe la emit et la insertItems fonction des appels et définir un point d' arrêt sur la emit déclaration, le point d' arrêt est jamais atteint, si l'exécution doit avoir été interrompu en essayant de conserver les données. BTW, merci pour la pointe avec .collect() !



0
votes

Désolé les gars ... Il n'y a aucun problème avec le code de mon message d'origine. Je n'ai pas évalué l'erreur que j'ai lancée lors de la capture de l'exception. Le problème était donc complètement différent (la contrainte NOT NULL a échoué).

Je n'y ai pas pensé à cause du message avec le fil principal.

Merci à tous pour votre aide.


0 commentaires