次のユースケースがあります:ユーザーが登録フォームにアクセスし、名前、メール、パスワードを入力して、登録ボタンをクリックします。そのシステムは、電子メールが取得されたかどうかを確認する必要があり、そのエラーメッセージの表示または新しいユーザーの作成に基づいて...
Room、ViewModel、LiveDataを使用してそれをしようとしています。これは、これらのコンポーネントを学習しようとするプロジェクトであり、リモートAPIを持っていないため、ローカルデータベースにすべてを保存します
だから私はこれらのクラスを持っています:
したがって、私が考えているのは、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に変更する方法です...
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
私のヘルパーメソッドを使用できます:
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
}
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
}
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>
ペアの代わりなど。