web-dev-qa-db-fra.com

Comment combiner deux données en direct l'une après l'autre?

J'ai le prochain cas d'utilisation: l'utilisateur vient au formulaire d'inscription, saisit le nom, l'e-mail et le mot de passe et clique sur le bouton d'enregistrement. Après cela, le système doit vérifier si le courrier électronique est pris ou non et en fonction de ce message d'erreur ou de créer un nouvel utilisateur ...

J'essaie de le faire en utilisant Room, ViewModel et LiveData. C'est un projet sur lequel j'essaye d'apprendre ces composants et je n'ai pas d'api distant, je vais tout stocker dans la base de données locale

J'ai donc ces cours:

  • RegisterActivity
  • RegisterViewModel
  • Utilisateur
  • UtilisateursDAO
  • UsersRepository
  • UsersRegistrationService

Donc, l'idée que j'ai est qu'il y aura un écouteur attaché au bouton d'enregistrement qui appellera la méthode RegisterViewModel::register().

class RegisterViewModel extends ViewModel {

    //...

    public void register() {
        validationErrorMessage.setValue(null);
        if(!validateInput())
            return;
        registrationService.performRegistration(name.get(), email.get(), password.get());
    }

    //...

}

C'est donc l'idée de base, je veux aussi que performRegistration me rende l'utilisateur nouvellement créé.

La chose qui me dérange le plus est que je ne sais pas comment implémenter la fonction performRegistration dans le service

class UsersRegistrationService {
    private UsersRepository usersRepo;

    //...

    public LiveData<RegistrationResponse<Parent>>  performRegistration(String name, String email, String password) {
         // 1. check if email exists using repository
         // 2. if user exists return RegistrationResponse.error("Email is taken") 
         // 3. if user does not exists create new user and return RegistrationResponse(newUser)
    }
}

Si je comprends bien, les méthodes qui sont dans UsersRepository devraient retourner LiveData parce que UsersDAO renvoie LiveData

@Dao
abstract class UsersDAO { 
    @Query("SELECT * FROM users WHERE email = :email LIMIT 1")
    abstract LiveData<User> getUserByEmail(String email);
}

class UsersRepository {
    //...
    public LiveData<User> findUserByEmail(String email) {
        return this.usersDAO.getUserByEmail(email);
    }
}

Mon problème est donc de savoir comment implémenter la fonction performRegistration() et comment transmettre la valeur au modèle de vue, puis comment modifier l'activité de RegisterActivity à MainActivity ...

8
clzola

Avec l'aide de MediatorLiveData , vous pouvez combiner les résultats de plusieurs sources. Voici un exemple de la façon dont je combinerais deux sources:

class CombinedLiveData<T, K, S>(source1: LiveData<T>, source2: LiveData<K>, private val combine: (data1: T?, data2: K?) -> S) : MediatorLiveData<S>() {

private var data1: T? = null
private var data2: K? = null

init {
    super.addSource(source1) {
        data1 = it
        value = combine(data1, data2)
    }
    super.addSource(source2) {
        data2 = it
        value = combine(data1, data2)
    }
}

override fun <T : Any?> addSource(source: LiveData<T>, onChanged: Observer<T>) {
    throw UnsupportedOperationException()
}

override fun <T : Any?> removeSource(toRemote: LiveData<T>) {
    throw UnsupportedOperationException()
}
}

voici l'essentiel ci-dessus, au cas où il serait mis à jour sur l'avenir: https://Gist.github.com/guness/0a96d80bc1fb969fa70a5448aa34c215

12
guness

Jose Alcérreca a probablement le meilleure réponse à cela :

fun blogpostBoilerplateExample(newUser: String): LiveData<UserDataResult> {

    val liveData1 = userOnlineDataSource.getOnlineTime(newUser)
    val liveData2 = userCheckinsDataSource.getCheckins(newUser)

    val result = MediatorLiveData<UserDataResult>()

    result.addSource(liveData1) { value ->
        result.value = combineLatestData(liveData1, liveData2)
    }
    result.addSource(liveData2) { value ->
        result.value = combineLatestData(liveData1, liveData2)
    }
    return result
}
3
Daniel Wilson

Vous pouvez définir une méthode qui combinerait plusieurs LiveDatas à l'aide d'un MediatorLiveData, puis exposer ce résultat combiné en tant que Tuple.

public class CombinedLiveData2<A, B> extends MediatorLiveData<Pair<A, B>> {
    private A a;
    private B b;

    public CombinedLiveData2(LiveData<A> ld1, LiveData<B> ld2) {
        setValue(Pair.create(a, b));

        addSource(ld1, (a) -> { 
             if(a != null) {
                this.a = a;
             } 
             setValue(Pair.create(a, b)); 
        });

        addSource(ld2, (b) -> { 
            if(b != null) {
                this.b = b;
            } 
            setValue(Pair.create(a, b));
        });
    }
}

Si vous avez besoin de plus de valeurs, vous pouvez créer un CombinedLiveData3<A,B,C> et exposez un Triple<A,B,C> au lieu de la paire, etc.

0
EpicPandaForce