web-dev-qa-db-ja.com

2つのライブデータを次々に結合する方法は?

次のユースケースがあります:ユーザーが登録フォームにアクセスし、名前、メール、パスワードを入力して、登録ボタンをクリックします。そのシステムは、電子メールが取得されたかどうかを確認する必要があり、そのエラーメッセージの表示または新しいユーザーの作成に基づいて...

Room、ViewModel、LiveDataを使用してそれをしようとしています。これは、これらのコンポーネントを学習しようとするプロジェクトであり、リモートAPIを持っていないため、ローカルデータベースにすべてを保存します

だから私はこれらのクラスを持っています:

  • RegisterActivity
  • RegisterViewModel
  • ユーザー
  • ユーザーDAO
  • ユーザーリポジトリ
  • UsersRegistrationService

したがって、私が考えているのは、RegisterViewModel::register()メソッドを呼び出す登録ボタンに接続されたリスナーがあるということです。

_class RegisterViewModel extends ViewModel {

    //...

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

    //...

}
_

それが基本的な考え方です。また、performRegistrationが新しく作成したユーザーに戻りたいと思っています。

最も気になるのは、サービスにperformRegistration関数を実装する方法がわからないことです。

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

私が理解しているように、UsersRepositoryがLiveDataを返すため、UsersDAOにあるメソッドは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);
    }
}
_

だから私の問題は、performRegistration()関数を実装する方法と、ビューモデルに値を戻す方法と、アクティビティをRegisterActivityからMainActivityに変更する方法です...

8
clzola

MediatorLiveData を使用すると、複数のソースからの結果を組み合わせることができます。ここで、2つのソースをどのように組み合わせるかの例を示します。

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

将来更新される場合の上記の要点は次のとおりです。 https://Gist.github.com/guness/0a96d80bc1fb969fa70a5448aa34c215

12
guness

私のヘルパーメソッドを使用できます:

val profile = MutableLiveData<ProfileData>()

val user = MutableLiveData<CurrentUser>()

val title = profile.combineWith(user) { profile, user ->
    "${profile.job} ${user.name}"
}

fun <T, K, R> LiveData<T>.combineWith(
    liveData: LiveData<K>,
    block: (T?, K?) -> R
): LiveData<R> {
    val result = MediatorLiveData<R>()
    result.addSource(this) {
        result.value = block.invoke(this.value, liveData.value)
    }
    result.addSource(liveData) {
        result.value = block.invoke(this.value, liveData.value)
    }
    return result
}
4
Marek Kondracki

JoseAlcérrecaにはおそらく これに対するベストアンサー

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

MediatorLiveDataを使用して複数のLiveDataを結合するメソッドを定義し、この結合結果を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));
        });
    }
}

さらに値が必要な場合は、CombinedLiveData3<A,B,C>およびTriple<A,B,C>ペアの代わりなど。

0
EpicPandaForce