web-dev-qa-db-ja.com

オブジェクトフィールドの変更に関するLiveDataの更新

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で文字列などのプライマリ値を使用しないことが重要です。

28
Reza A. Ahmadi

このために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でこのプロパティ変更コールバックを使用して、オブザーバーに通知するだけです。このためにカスタム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());

        }
    };


}

次に、ビューモデルでMutableLiveDataの代わりにこのCustomMutableLiveDataを使用するだけです。

public class InfoViewModel extends AndroidViewModel {

    CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----

そのため、これを行うことで、既存のコードをほとんど変更することなく、ビューとLiveDataの両方のオブザーバーに通知できます。それが役に立てば幸い

34
Abhishek V

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}"
        />
11
sonique

オブザーバーに通知するには、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);

オブジェクト全体を更新するのではなく、オブジェクトから1つのフィールドのみを更新する場合は、倍数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
});
0
florian-do