我在LiveData中使用Android MVVM架构。我有一个这样的对象
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
我的视图模型看起来像这样
public class InfoViewModel extends AndroidViewModel {
MutableLiveData<User> user = new MutableLiveData<>();
public InfoViewModel(@NonNull Application application) {
super(application);
User user = new User();
user.setFirstName("Alireza");
user.setLastName("Ahmadi");
this.user.setValue(user);
}
public LiveData<User> getUser(){
return user;
}
public void change(){
user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
}
}
如何确保用户对象中的某些变更观察者收到通知?顺便说一下,将这些数据保存在单独的对象中并且不在我的ViewModel中使用像字符串这样的主要值这一点很重要。
答案 0 :(得分:26)
我认为没有像Android推荐的最佳做法。我建议你使用使用清洁剂和清洁剂的方法。更少的样板代码。
如果您使用Android数据绑定以及LiveData
,您可以采用以下方法:
您的POJO对象看起来像这样
public class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
@Bindable
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
因此,您将拥有一个在其属性发生变化时通知的类。因此,您可以在MutableLiveData中使用此属性更改回调来通知其观察者。您可以为此
创建自定义MutableLiveDatapublic class CustomMutableLiveData<T extends BaseObservable>
extends MutableLiveData<T> {
@Override
public void setValue(T value) {
super.setValue(value);
//listen to property changes
value.addOnPropertyChangedCallback(callback);
}
Observable.OnPropertyChangedCallback callback = new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
//Trigger LiveData observer on change of any property in object
setValue(getValue());
}
};
}
然后您需要做的就是在View模型中使用此CustomMutableLiveData而不是MutableLiveData
public class InfoViewModel extends AndroidViewModel {
CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
通过这样做你可以通知视图和&amp; LiveData观察者对现有代码几乎没有任何改变。希望它有所帮助
答案 1 :(得分:8)
如果您使用的是Kotlin和LiveData,我可以为您提供2种方法-带有和不带有扩展功能:
import React, { useState, useEffect } from "react";
import {
StyleSheet,
View,
Text,
ActivityIndicator,
TouchableOpacity,
TextInput
} from "react-native";
import * as firebase from "firebase";
const AccountScreen = () => {
const db = firebase.firestore();
let user = firebase.auth().currentUser;
const [user_data, set_user_data] = useState(null);
const SignOut = () => {
set_user_data(null);
firebase
.auth()
.signOut()
.then(() => {
console.log("successfully logged out");
})
.catch(error => {
// An error happened.
console.log("error logging out" + error);
});
};
if (user) {
useEffect(() => {
db.doc(`users/${user.uid}`)
.get()
.then(doc => {
set_user_data(doc.data());
})
.catch(error => {
console.log("Error getting document:", error);
});
}, []);
if (!user_data) {
console.log("uh oh! there's a user but they don't have any data");
return (
<View style={styles.container}>
<ActivityIndicator
animating={true}
style={styles.indicator}
size="large"
/>
</View>
);
} else if (user_data) {
console.log("nice! there's a user and they have data");
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.submitButton}
onPress={() => SignOut()}
>
<Text style={styles.submitButtonText}>Sign Out</Text>
</TouchableOpacity>
</View>
);
}
} else {
console.log("no user at all!!");
return (
<View>
<Text>There's an error here</Text>
</View>
);
}
};
export default AccountScreen;
liveData.value = liveData.value?.also { it ->
// Modify your object here. Data will be auto-updated
it.name = "Ed Khalturin"
it.happyNumber = 42
}
答案 2 :(得分:7)
使用MVVM和LiveData时,您可以将对象重新绑定到布局,这样它将触发UI上的所有更改。
在ViewModel中,“用户”为MutableLiveData<User>
ViewModel
class SampleViewModel : ViewModel() {
val user = MutableLiveData<User>()
fun onChange() {
user.value.firstname = "New name"
user.value = user.value // force postValue to notify Observers
// can also use user.postValue()
}
}
活动/片段文件:
viewModel = ViewModelProviders
.of(this)
.get(SampleViewModel::class.java)
// when viewModel.user changes, this observer get notified and re-bind
// the user model with the layout.
viewModel.user.observe(this, Observer {
binding.user = viewModel.user //<- re-binding
})
您的布局文件不应更改:
<data>
<variable
name="user"
type="com.project.model.User" />
</data>
...
<TextView
android:id="@+id/firstname"
android:text="@{user.firstname}"
/>
答案 3 :(得分:1)
来自reddit - @cedrickc's answer :
为 MutableLiveData 添加一个扩展函数:
fun <T> MutableLiveData<T>.modifyValue(transform: T.() -> T) {
this.value = this.value?.run(transform)
}
答案 4 :(得分:0)
如果您的观察者收到通知,您应该使用setValue
user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
您的观察者不会收到通知!
查看模型
public MutableLiveData<User> getUser() {
return user;
}
活动/片段
mModel = ViewModelProviders.of(this).get(InfoViewModel.class);
mModel.getUser().observe(this, s -> {
// User has been modified
});
活动/片段中的某个地方
这将触发观察者:
mModel.getUser().setValue(user);
如果您只想更新对象中的一个字段而不是更新整个对象,则应该有倍数MutableLiveData<String>
// View Model
private MutableLiveData<String> firstName;
private MutableLiveData<String> lastName;
//Somewhere in your code
mModel.getFirstName().setValue(user.getValue().getFirstName() + " A ");
mModel.getFirstName().observe(this, s -> {
// Firstname has been modified
});
答案 5 :(得分:0)
我如何确定何时在用户对象中归档某些字段来更改观察者 得到通知?顺便说一句,对我来说,将这些数据保存在 单独的对象,并且在 ViewModel。
您可以使用androidx.lifecyle.Transformation类监视各个字段。
val user = MutableLiveData<User>();
//to monitor for User.Name
val firstName: LiveData<String> = Transformations.map {it.firstName}
val lastName: LiveData<String> = Transformations.map {it.lastName}
您可以正常更新用户,并监听名字/姓氏以监视这些字段中的更改。