问题
If MVVM is all about data binding and cannot do something like view.doThis()
, otherwise it's MVP, then how to invoke actions on views?
Suppose I have view that has a snackbar
. View
is controlled by its ViewModel
. How is this ViewModel
supposed to show snackbar
without going snackbar.show()
?
回答1:
In MVVM, ViewModel captures the state of the view. View observes the ViewModel for changes and updates itself. Thus, the communication between View & ViewModel happens through change of values (as against method calls in MVP).
Since Snackbar
is like a global behaviour (like Toast), it can be implemented at the Activity/Fragment level. So, you can make a MessageHelper
interface and pass it to the ViewModel as a dependency. Activity will implement it and display Snackbar
.
Example:
- ItemViewModel that consumes the interface
- Activity base class that implements the interface
However, its possible that there is some view specific behaviour which cannot be implemented at the Activity level. For such cases, you can make use of databinding.Observable
to trigger an event. For example, lets say we want to animate a particular view. We can create a BindingAdapter
@BindingAdapter({"shakeTrigger"})
public static void showSnackbar(View view, Void trigger) {
// Do the animation here. You could add meaningful argument types to control the animation
}
In XML, we can apply this using
<TextView
bind:shakeTrigger="@{vm.shakeTrigger}"/>
Then, in the viewModel, you can trigger the shake using Data Binding apis. One way using BaseObservable
can be:
public class ConfigurationViewModel extends BaseObservable implements ViewModel {
@Bindable
public final Void shakeTrigger = null;
public void shake() {
notifyPropertyChanged(BR.shakeTrigger);
}
}
If you use RxJava, the trigger could be implemented from rx.Observable
. You can checkout my library to use RxJava with Data Binding.
https://github.com/manas-chaudhari/android-mvvm
回答2:
The short answer is you don't and that's actually a good thing. In MVVM ViewModel is responsible for preparing and storing data for the view. So it gets the data from the model and makes it ready to be set on the view but it doesn't set the value, Setting the value and updating view states are responsibilities of the view itself, View in MVVM watches for changes in data and updates itself.
An example of this would be showing an empty list page when your list is empty. To do this in MVVM, you define a state for the view visibility in your ViewModel lets call it emptyPageVisibility
and then update this value appropriately.
public class PlaylistDetailViewModel extends ViewModel {
private MutableLiveData<Integer> emptyPageVisibility = new MutableLiveData<>();
private void someMethodInYourViewModel(){
emptyPageVisibility.setValue(View.VISIBLE);
}
}
Then inside your view, you observe this and update the view when this data is changed like this
viewModel.getEmptyPageVisibility().observe(this,
visibility -> emptyPageView.setVisibility(visibility));
来源:https://stackoverflow.com/questions/39637736/are-actions-allowed-in-mvvm-android