#android #firebase-realtime-database #android-livedata #mediatorlivedata
#Android #firebase-база данных в реальном времени #android-livedata #mediatorlivedata
Вопрос:
Вот моя проблема. Мне нужно сгенерировать данные из трех разных LiveData
объектов в один объект. Два из них зависят от одного из них. Наблюдатель должен запускаться только в том случае, если были получены все три объекта. Данные.
Вот пример:
Результирующий объект содержит информацию о продукте и конкретный рейтинг обзора этого продукта. Результирующий объект выглядит примерно так:
public class RatedProduct {
private String productKey; // database key to the product
private String ratingKey; // database key to the specific rating
private Product product; // the product information
private Rating rating; // the specifiv rating information
private HashMap<String, Boolean> customTags; // list of tags
...
}
Источники распределены по разным базам данных.
Первый объект UserRating
содержит дополнительные данные ( customTags
) и только два ключа, ссылающихся на продукт и на информацию о рейтинге.
public class UserRating {
private String ratingKey;
private String productKey;
private HashMap<String, Boolean> customTags;
...
}
Объекты Rating
и Product
содержат определенную информацию.
public class Rating {
private float value; // value of the rating
private String productKey; // database key to the product
private String ratingComment;
...
}
public class Product {
private String name; // name of the product
private HashMap<String, Boolean> ratings; // list of all ratings
...
}
Задача состоит в том, чтобы собрать все данные из UserRating
Rating
и Product
в один RatedProduct
, но скрыть необходимые шаги.
Я думаю, что лучший способ — использовать три разных LiveData
объекта и объединить их с помощью MediatorLiveData
Но я не уверен, как это сделать правильно. Я немного застрял. Я знаю, как добавить UserRatingLiveData
источник as MediatorLiveData
в, но я не понимаю, как добавить оставшиеся два, вызвать их RatingLiveData
и ProductLiveData
в отношении ключей, содержащихся UserRatingLiveData
в.
Вторая проблема заключается в том, что MediatorLiveData<RatedProduct>
обновление должно выполняться только в том случае, если были получены все данные, а не только один из них.
Это то, что у меня есть (более или менее ничего). Интересная часть LiveData<RatedProduct> getRatedProductLiveData()
, я думаю:
public class UserViewModel extends ViewModel {
...
private UserRatingsLiveData mUserRatingsLiveDate;
public UserViewModel() {
//
// Getting current user
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
if (mUser != null) {
this.mUserRatingsLiveDate =
new UserRatingsLiveData(
mUsersDatabaseReference.child(mUser.getUid() "/" DB_PATH_RATINGS));
} else {
Log.d(LOG_TAG, "mUser is NULL");
}
}
@NonNull
public LiveData<RatedProduct> getRatedProductLiveData() {
final MediatorLiveData<RatedProduct> liveDataMerger = new MediatorLiveData<> ();
final UserRating receivedUserRating = new UserRating();
liveDataMerger.addSource(this.mUserRatingsLiveDate, new Observer<UserRating>() {
public void onChanged(UserRating userRatings) {
}
});
return liveDataMerger;
}
}
В качестве дополнительной подсказки: база данных — это база данных Firebase RealTimeDatabase, если это может помочь.
Ответ №1:
Попробуйте так:
class MyViewModel {
val mainLiveData: LiveData<CustomClass> get() = _mainLiveData
private val firstLiveData = MutableLiveData<String>()
private val secondLiveData : MutableLiveData<Int>? = null
private val thirdLiveData : MutableLiveData<Long>? = null
private val _mainLiveData = MediatorLiveData<CustomClass>().also { mergeLiveData ->
mergeLiveData.addSource(firstLiveData) {
if (secondLiveData != null ) mergeLiveData.removeSource(secondLiveData)
if (thirdLiveData != null) mergeLiveData.removeSource(thirdLiveData)
secondLiveData = getSecondLiveData(firstLiveData.value)
thirdLiveData = getThirdLiveData(firstLiveData.value)
mergeLiveData.addSource(secondLiveData) {
updateMainLiveData(mergeLiveData)
}
mergeLiveData.addSource(thirdLiveData) {
updateMainLiveData(mergeLiveData)
}
}
}
private fun updateMainLiveData(mainLiveData: MediatorLiveData<CustomClass>) {
val first = firstLiveData.value ?: return
val second = secondLiveData.value ?: return
val third = thirdLiveData.value ?: return
mainLiveData.value = CustomClass(first, second, third)
}
data class CustomClass(
val first: String,
val second: Int,
val third: Long
)
}
Комментарии:
1. Вау, это было быстро. Спасибо. Я попробую, но сначала мне нужен ускоренный курс по Kotlin: D Насколько я понимаю ваш подход, он будет работать, только если вы знаете все источники базы данных трех
LiveData
объектов одновременно. В моем случае я сначалаfirstLiveData
не, потому что он содержит ключиsecondLiveData
иthirdLiveData
. После этого я могу добавить их в качестве источникаmergeLiveData
. Я прав?2. Какой тип mergeLiveData или это Kotlin, что для них нет определения?
3. В блоке
also
мы можем указать имя для этой переменной.mergeLiveData
то есть_mainLiveData = MediatorLiveData<CustomClass>()
, только для использования вalso
блоке, я даю такое имя.