我正在尝试使用MVVM模式创建一个简单的“登录”屏幕。我的View
和Model
类之间有双向数据绑定,但是ViewModel
要做什么呢?
最初,我认为我什至没有Model
类,而我的ViewModel
类将具有与View
进行双向数据绑定的属性,但是{{ 1}}类已经扩展了必须在Fragment中膨胀的类,因此不能扩展ViewModel
以允许双向数据绑定。
我通常对这些组件之间应该如何交互或者我需要/不需要什么感到困惑。
我的片段(查看)
BaseObservable
还有一些我的login_fragment.xml
public class LoginFragment extends Fragment {
private LoginViewModel mViewModel;
public static LoginFragment newInstance() {
return new LoginFragment();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
LoginFragmentBinding binding = LoginFragmentBinding.inflate(inflater, container, false);
binding.setViewModel(mViewModel); // mViewModel is null here...
binding.setLoginInfo(new LoginInfo());
return binding.getRoot();
}
}
我的ViewModel类
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable name="viewModel" type="login.ui.LoginViewModel"/>
<variable name="loginInfo" type="login.ui.model.LoginInfo" />
</data>
<android.support.constraint.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".login.ui.LoginFragment">
<EditText
android:id="@+id/input_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:autofillHints="password"
android:ems="10"
android:hint="@string/hint_password"
android:inputType="textPassword"
android:text="@={loginInfo.password}"
app:layout_constraintBottom_toTopOf="@id/button_sign_in"
app:layout_constraintEnd_toEndOf="@id/input_username"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@id/input_username"
app:layout_constraintTop_toBottomOf="@id/input_username" />
<EditText
android:id="@+id/input_username"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_marginTop="285dp"
android:autofillHints="username"
android:ems="10"
android:hint="@string/hint_username"
android:inputType="textEmailAddress"
android:text="@={loginInfo.username}"
app:layout_constraintBottom_toTopOf="@id/input_password"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_sign_in"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/hint_sign_in"
android:onClick="@{()-> viewModel.onSignInClicked(loginInfo)}"
app:layout_constraintBottom_toTopOf="@id/button_create_account"
app:layout_constraintEnd_toEndOf="@id/input_password"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@id/input_password"
app:layout_constraintTop_toBottomOf="@id/input_password" />
我的LoginInfo(模型)类
public class LoginViewModel extends ViewModel {
// Want to bind this to a button in the XML, but
// the mViewModel instance in the LoginFragment isnt assigned
public void onSignInClicked(LoginInfo info) {
Log.i("Username", info.getUsername());
Log.i("Password", info.getPassword());
// TODO: Actual log in attempt
}
}
答案 0 :(得分:1)
我认为您对MVVM有点困惑。
在 MVVM(模型-视图-视图模型)中,模型类和视图类之间没有直接通信。我记得写为 M-VM-V 。这意味着,您的视图(片段,活动,xml)将与VM通信,反之亦然。然后,您的模型(数据类,pojo)将与viewModel类进行通信,反之亦然。
因此,您不应同时在XML中使用视图模型和模型。在视图模型类中保留模型的引用以设置数据并获取数据。使用具有可观察对象的视图模型与xml进行数据绑定。
此外,您永远不要在任何视图类的任何地方编写viewModel.getModel().getSomething()
。而是在视图模型中创建一个返回该值的方法。这就是在不更改任何视图类中的一行的情况下替换模型类变得多么容易的事情。
答案 1 :(得分:0)
所有MV *模式旨在促进交互层和业务逻辑之间的松散耦合。
在MVVM中,您的视图应了解您的模型,但切勿对其进行中继。
VM的工作是从模型中获取数据并以View可以显示给用户的方式进行解析。
答案 2 :(得分:0)