web-dev-qa-db-fra.com

Comment chaîner des transformations dans Android lors de l'utilisation de données en direct?

Compte tenu de la configuration suivante:

J'ai 2 référentiels: Repository A et Repository B tous les deux renvoient des données actives.

J'ai un ViewModel qui utilise ces deux référentiels.

Je souhaite extraire quelque chose du référentiel A et en fonction du résultat, je souhaite extraire quelque chose du référentiel B, puis transformer le résultat avant de revenir à l'interface utilisateur. 

Pour cela, je me suis intéressé aux classes LiveData Transformation . Les exemples montrent une seule transformation du résultat, mais je souhaite quelque chose dans le sens de l'enchaînement de deux transformations. Comment puis-je accomplir cela?

J'ai essayé de mettre en place quelque chose comme ça, mais il y a une incompatibilité de type sur le deuxième bloc de transformation:

  internal val launchStatus: LiveData<String> = Transformations
        .map(respositoryA.getData(), { data ->
            if (data.isValid){
                "stringA"
            } else {
                //This gives a type mismatch for the entire block
                Transformations.map(repositoryB.getData(), {
                    result -> result.toString()
                })
            }
        })

(Veuillez également me faire savoir s'il existe une approche alternative/recommandée pour saisir quelque chose pour les chaîner, par exemple, saisir quelque chose de A puis prendre quelque chose de B en fonction du résultat de A, etc.)

7
Naveed

J'ai utilisé MediatorLiveData pour résoudre ce problème. 

MediatorLiveData peut observer d'autres objets LiveData et y réagir.

Au lieu d’observer l’un des dépôts. J'ai créé myData (instance de MediatorLiveData) dans ma classe ViewModel et j'ai le droit d'observer cet objet. J'ajoute ensuite le référentiel A en tant que source initiale et observe cela et ajoute uniquement Repository B si le résultat de A le requiert. Cela me permet de conserver les transformations associées aux données en temps réel de chaque rapport et de traiter chaque résultat dans le bon ordre. Voir ci-dessous pour la mise en œuvre:

internal val myData: MediatorLiveData<String> = MediatorLiveData()

private val repoA: LiveData<String> = Transformations.map(
        respositoryA.getData(), { data ->
    if (data.isValid) "stringA" else ""

})

private val repoB: LiveData<String> = Transformations.map(
        repositoryB.getData(), { data -> "stringB" 
})

fun start() {
    myData.addSource(repoA, {
        if (it == "stringA") {
            myData.value = it
        } else {
            myData.addSource(repoB, {
                myData.value = it
            })
        }
    })
}

Note: La solution ne couvre pas le cas où le repoB pourrait être ajouté plusieurs fois, mais il devrait être assez simple à gérer.

4
Naveed

Votre lambda renvoie parfois la String"stringA" et parfois le LiveData<String> donné par:

Transformations.map(repositoryB.getData(), {
    result -> result.toString()
})

Cela signifie que votre lambda n'a pas de sens - il renvoie différentes choses dans différentes branches.

Comme d'autres l'ont déjà mentionné, vous pourriez écrire votre propre MediatorLiveData au lieu d'utiliser celle donnée par Transformations. Cependant, je pense qu'il est plus facile de faire ce qui suit:

internal val launchStatus: LiveData<String> = Transformations
    .switchMap(respositoryA.getData(), { data ->
        if (data.isValid) {
            MutableLiveData().apply { setValue("stringA") }
        } else {
            Transformations.map(repositoryB.getData(), {
                result -> result.toString()
            })
        }
    })

Tout ce que j'ai fait est de faire en sorte que la première branche de code retourne également un LiveData<String>; votre lambda est donc logique - c'est un (String) -> LiveData<String> Je devais faire un autre changement: utiliser switchMap au lieu de map. En effet, map prend un lambda (X) -> Y, mais switchMap prend un lambda (X) -> LiveData<Y>.

3
Chrispher

J'essaierais d'utiliser switchMap au lieu de map:

Comme pour map (), applique une fonction à la valeur stockée dans l'objet LiveData, décompresse et distribue le résultat en aval. La fonction transmise à switchMap () doit renvoyer un objet LiveData.

0
Salvatore-Giordano

Vous pouvez transformer les données en utilisant switchmap. Voici un exemple documentation .

0
Ben Lewis