对象字段更改的LiveData更新

Rez*_*adi 33 android observable android-livedata android-viewmodel

我正在使用带有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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的视图模型看起来像这样

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 ");
    }
}
Run Code Online (Sandbox Code Playgroud)

如何确保用户对象中的某些变更观察者得到通知?BTW它保持在单独的对象这个数据和我的视图模型不使用像弦乐首要价值是对我很重要.

Abh*_*k V 37

我不认为有任何最好的做法,因为这是由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);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,您将拥有一个在其属性发生变化时通知的类.因此,您可以在MutableLiveData中使用此属性更改回调来通知其观察者.您可以为此创建自定义MutableLiveData

public 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());

        }
    };


}
Run Code Online (Sandbox Code Playgroud)

然后,您需要做的就是在View Model中使用此CustomMutableLiveData而不是MutableLiveData

public class InfoViewModel extends AndroidViewModel {

    CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
Run Code Online (Sandbox Code Playgroud)

因此,通过这样做,您可以通过对现有代码的少量更改来通知view和LiveData观察者.希望能帮助到你

  • 有没有办法在没有数据绑定的情况下做到这一点?我的意思是,像这样的方法,您可以选择何时更改 liveData 的值。 (2认同)

DVe*_*asa 15

如果您使用 Kotlin 和 LiveData,我可以为您提供 2 种方式 - 有和没有扩展功能:

无扩展功能

liveData.value = liveData.value?.also { it ->
    // Modify your object here. Data will be auto-updated
    it.name = "Ed Khalturin"
    it.happyNumber = 42
}
Run Code Online (Sandbox Code Playgroud)

相同,但有扩展

// Extension. CopyPaste it anywhere in your project
fun <T> MutableLiveData<T>.mutation(actions: (MutableLiveData<T>) -> Unit) {
    actions(this)
    this.value = this.value
}

// Usage
liveData.mutation {
    it.value?.name = "Ed Khalturin"
    it.value?.innerClass?.city= "Moscow" // it works with inner class too
}
Run Code Online (Sandbox Code Playgroud)

  • 好想法。我将通过使用“actions: MutableLivedata&lt;T&gt;.() -&gt; Unit”进一步增强它,这样 lambda 就可以在没有“it”的情况下编写 (2认同)
  • 它应该如何工作?这只会触发一次(在初始化期间),而不是每次值更改时触发 (2认同)

son*_*que 12

使用MVVM和LiveData时,您可以将对象重新绑定到布局,这样它将触发UI上的所有更改。

给定“用户”是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()
    }
}
Run Code Online (Sandbox Code Playgroud)

活动/片段文件:

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
})
Run Code Online (Sandbox Code Playgroud)

您的布局文件不应更改:

<data>
    <variable
        name="user"
        type="com.project.model.User" />
</data>

...

<TextView
        android:id="@+id/firstname"
        android:text="@{user.firstname}"
        />
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说似乎是错误的。使用 LiveData 的全部目的不就是不重新绑定吗? (16认同)
  • 这是有效的!但是重新绑定是否有任何性能缺陷? (2认同)
  • 这不是重新绑定,它只是刷新变量,这将反映 UI 上的更改。没看出这里有什么问题。 (2认同)

Ang*_*Koh 5

如何确保用户对象更改时观察者会收到通知?顺便说一句,对我来说,将这些数据保存在单独的对象中并且不要在 ViewModel 中使用诸如字符串之类的主要值非常重要。

您可以使用 androidx.lifecyle.Transformation 类来监视各个字段。

val user = MutableLiveData<User>();
//to monitor for User.Name
val firstName: LiveData<String>  = Transformations.map(user) {it.firstName}
val lastName: LiveData<String>  = Transformations.map(user) {it.lastName}
Run Code Online (Sandbox Code Playgroud)

您按照正常方式更新用户,并侦听名字/姓氏以监视这些字段中的更改。


avi*_*per 5

来自reddit - @cedrickc 的回答

向 MutableLiveData 添加扩展函数:

fun <T> MutableLiveData<T>.modifyValue(transform: T.() -> T) {
   this.value = this.value?.run(transform)
}
Run Code Online (Sandbox Code Playgroud)

  • fun &lt;T&gt; MutableLiveData&lt;T&gt;.setField(transform: T.() -&gt; Unit) { this.value = this.value?.apply(transform) } (5认同)