MVVM和两种方式的数据绑定混乱

时间:2018-10-19 03:24:25

标签: android mvvm android-databinding 2-way-object-databinding android-jetpack

我正在尝试使用MVVM模式创建一个简单的“登录”屏幕。我的ViewModel类之间有双向数据绑定,但是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
    }
}

3 个答案:

答案 0 :(得分:1)

我认为您对MVVM有点困惑。

MVVM(模型-视图-视图模型)中,模型类和视图类之间没有直接通信。我记得写为 M-VM-V 。这意味着,您的视图(片段,活动,xml)将与VM通信,反之亦然。然后,您的模型(数据类,pojo)将与viewModel类进行通信,反之亦然。

因此,您不应同时在XML中使用视图模型和模型。在视图模型类中保留模型的引用以设置数据并获取数据。使用具有可观察对象的视图模型与xml进行数据绑定。

此外,您永远不要在任何视图类的任何地方编写viewModel.getModel().getSomething()。而是在视图模型中创建一个返回该值的方法。这就是在不更改任何视图类中的一行的情况下替换模型类变得多么容易的事情。

答案 1 :(得分:0)

所有MV *模式旨在促进交互层和业务逻辑之间的松散耦合。

在MVVM中,您的视图应了解您的模型,但切勿对其进行中继。

VM的工作是从模型中获取数据并以View可以显示给用户的方式进行解析。

答案 2 :(得分:0)

MVVM中各层之间的划分有些许灰色区域。

我个人来说,分割方式是

  • 模型-仅是应用程序数据,仅此而已-通常作为简单的POCO类。

  • 视图-用户界面,此处没有业务逻辑。

  • ViewModel -其他所有内容。 ViewModel的主要角色是View的主要控制器和数据提供者。这可以采取直接暴露用于数据绑定的模型对象,(其他子ViewModel对象的集合)U.I命令的形式。触发处理,(注入)服务,例如外部数据存储和检索。

有关我最近的博客文章的更多详细信息-Model / ViewModel。是的,我知道这个问题被标记为Android,并且我的博客主要关注WPF,但是一般原则仍然适用。