Android 如何依次组合两个实时数据?
我有下一个用例:用户来到注册表单,输入姓名、电子邮件和密码,然后点击注册按钮。之后,系统需要检查电子邮件是否被接收,并根据显示的错误消息或创建新用户 我正在尝试使用Room、ViewModel和LiveData来实现这一点。这是一个我试图学习这些组件的项目,我没有远程api,我将把所有东西都存储在本地数据库中 所以我有这些课程:Android 如何依次组合两个实时数据?,android,observer-pattern,android-room,android-architecture-components,android-livedata,Android,Observer Pattern,Android Room,Android Architecture Components,Android Livedata,我有下一个用例:用户来到注册表单,输入姓名、电子邮件和密码,然后点击注册按钮。之后,系统需要检查电子邮件是否被接收,并根据显示的错误消息或创建新用户 我正在尝试使用Room、ViewModel和LiveData来实现这一点。这是一个我试图学习这些组件的项目,我没有远程api,我将把所有东西都存储在本地数据库中 所以我有这些课程: 注册活动 RegisterViewModel 使用者 UsersDAO 用户还原 用户注册服务 所以我的想法是,将有一个监听器连接到register按钮,它将调用R
- 注册活动
- RegisterViewModel
- 使用者
- UsersDAO
- 用户还原
- 用户注册服务
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)
}
}
因此,我的问题是如何实现performRegistration()
函数,如何将值传递回视图模型,然后如何将活动从RegisterActivity更改为MainActivity…在的帮助下,您可以组合来自多个源的结果。下面是如何组合两个来源的示例:
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 <S : Any?> addSource(source: LiveData<S>, onChanged: Observer<in S>) {
throw UnsupportedOperationException()
}
override fun <T : Any?> removeSource(toRemove: LiveData<T>) {
throw UnsupportedOperationException()
}
}
class-CombinedLiveData(source1:LiveData,source2:LiveData,private-val-combine:(data1:T?,data2:K?)->S:MediatorLiveData(){
私有变量数据1:T?=null
私有变量数据2:K?=null
初始化{
super.addSource(source1){
数据1=它
值=联合收割机(数据1、数据2)
}
super.addSource(source2){
数据2=它
值=联合收割机(数据1、数据2)
}
}
重写fun addSource(源:LiveData,onChanged:Observer){
抛出UnsupportedOperationException()
}
覆盖fun removeSource(toRemove:LiveData){
抛出UnsupportedOperationException()
}
}
以下是上述内容的要点,以备将来更新:
何塞·阿尔塞雷卡可能有:
fun blogpostBoilerplateExample(newUser:String):LiveData{
val liveData1=userOnlineDataSource.getOnlineTime(newUser)
val liveData2=userCheckinsDataSource.getCheckins(newUser)
val result=MediatorLiveData()
result.addSource(liveData1){value->
result.value=CombineRelatestData(liveData1、liveData2)
}
result.addSource(liveData2){value->
result.value=CombineRelatestData(liveData1、liveData2)
}
返回结果
}
您可以使用我的助手方法:
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(this.value, liveData.value)
}
result.addSource(liveData) {
result.value = block(this.value, liveData.value)
}
return result
}
val profile=MutableLiveData()
val user=MutableLiveData()
val title=profile.combineWith(user){profile,user->
“${profile.job}${user.name}”
}
有趣的LiveData.combineWith(
liveData:liveData,
块:(T?,K?)->R
):LiveData{
val result=MediatorLiveData()
result.addSource(此){
result.value=block(this.value,liveData.value)
}
result.addSource(liveData){
result.value=block(this.value,liveData.value)
}
返回结果
}
您可以定义一个方法,该方法将使用MediatorLiveData组合多个LiveData,然后将此组合结果作为元组公开
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));
});
}
}
公共类组合LiveData2
编辑:嘿,看,我甚至为你制作了一个从2个数组到16个数组的库:LiveData liveData1=。。。;
LiveData liveData2=。。。;
MediatorLiveData LiveDataMerge=新的MediatorLiveData();
addSource(liveData1,value->livedatamerge.setValue(value));
addSource(liveData2,value->livedatamerge.setValue(value));
我做了一个基于@guness answer的方法。我发现限制两个LiveData
s是不好的。如果我们想用3怎么办?我们需要为每个案例创建不同的类。因此,我创建了一个类来处理无限量的LiveData
s
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data results.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/
class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
/**
*CombinedLiveData是一个助手类,用于组合来自多个LiveData源的结果。
*@param liveDatas LiveData参数的变量数。
*@param combine函数引用,用于组合所有LiveData结果。
*@param R组合所有LiveData数据后返回的数据类型。
*用法:
*组合livedata(
*getLiveData1(),
*getLiveData2(),
* ... ,
*getLiveDataN()
*){数据:列表->
*//使用数据[0]、数据[1]、…、数据[N]返回SomeType值
* }
*/
类CombinedLiveData(vararg liveDatas:LiveData,
private-val-combine:(datas:List)->R:MediatorLiveData(){
私有val数据:MutableList=MutableList(liveDatas.size){null}
初始化{
对于(liveDatas.index中的i){
super.addSource(liveDatas[i]){
数据[i]=it
值=组合(数据)
}
}
}
}
如果希望两个值都不为null
fun <T, V, R> LiveData<T>.combineWithNotNull(
liveData: LiveData<V>,
block: (T, V) -> R
): LiveData<R> {
val result = MediatorLiveData<R>()
result.addSource(this) {
this.value?.let { first ->
liveData.value?.let { second ->
result.value = block(first, second)
}
}
}
result.addSource(liveData) {
this.value?.let { first ->
liveData.value?.let { second ->
result.value = block(first, second)
}
}
}
return result
}
fun LiveData.combineWithNotNull(
liveData:liveData,
块:(T,V)->R
):LiveData{
val result=MediatorLiveData()
result.addSource(此){
这个.value?.let{first->
liveData.value?.let{second->
result.value=块(第一,第二)
}
}
}
result.addSource(liveData){
这个.value?.let{first->
liveData.value?.let{second->
result.value=块(第一,第二)
}
}
}
返回结果
}
如果要在构建时创建字段并进行设置(也可以使用):
val liveData1=MutableLiveData(false)
val liveData2=MutableLiveData(false)
//如果liveData1和liveData2为true,则返回true
val liveDataCombined=MediatorLiveData(){
//初始值
it.value=false
//观察变化
it.addSource(liveData1){newValue->
它是瓦尔
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
/**
* CombinedLiveData is a helper class to combine results from multiple LiveData sources.
* @param liveDatas Variable number of LiveData arguments.
* @param combine Function reference that will be used to combine all LiveData data results.
* @param R The type of data returned after combining all LiveData data.
* Usage:
* CombinedLiveData<SomeType>(
* getLiveData1(),
* getLiveData2(),
* ... ,
* getLiveDataN()
* ) { datas: List<Any?> ->
* // Use datas[0], datas[1], ..., datas[N] to return a SomeType value
* }
*/
class CombinedLiveData<R>(vararg liveDatas: LiveData<*>,
private val combine: (datas: List<Any?>) -> R) : MediatorLiveData<R>() {
private val datas: MutableList<Any?> = MutableList(liveDatas.size) { null }
init {
for(i in liveDatas.indices){
super.addSource(liveDatas[i]) {
datas[i] = it
value = combine(datas)
}
}
}
}
fun <T, V, R> LiveData<T>.combineWithNotNull(
liveData: LiveData<V>,
block: (T, V) -> R
): LiveData<R> {
val result = MediatorLiveData<R>()
result.addSource(this) {
this.value?.let { first ->
liveData.value?.let { second ->
result.value = block(first, second)
}
}
}
result.addSource(liveData) {
this.value?.let { first ->
liveData.value?.let { second ->
result.value = block(first, second)
}
}
}
return result
}
val liveData1 = MutableLiveData(false)
val liveData2 = MutableLiveData(false)
// Return true if liveData1 && liveData2 are true
val liveDataCombined = MediatorLiveData<Boolean>().also {
// Initial value
it.value = false
// Observing changes
it.addSource(liveData1) { newValue ->
it.value = newValue && liveData2.value!!
}
it.addSource(selectedAddOn) { newValue ->
it.value = liveData1.value!! && newValue
}
}