【问题标题】:Android MVVM Design PatternAndroid MVVM 设计模式
【发布时间】:2014-08-31 23:10:24
【问题描述】:

我在最近发布的“Android 最佳实践”一书中读到,用于 android 编程的一个很好的设计模式是 MVVM。在我的最新项目中亲自尝试过它似乎确实有助于将代码分成更易于管理的部分。

View 只处理视图项的创建和 ViewModel 的接口。 ViewModel 实现对视图的接口和handlss 操作以及与模型的交互。示例代码如下:

型号

 public class MyModel{
    public String myString;
    public MyModel(String myString){
       this.myString = myString;
    }
}

查看

public class MyActivity{

    public ViewManager delegate;

    public interface ViewManager{
        void registerTextView(TextView tvText);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);
        delegate = new ViewController(this);
        TextView tvText = (TextView) view.findViewById(R.id.tvText);
        delegate.registerTextView(tvText);
    }
}

视图模型

 public class ViewController implements MyActivity.ViewManager{
     Context activity;
     TextView tvText;
     MyModel myModel;

     public ViewController(Context app_context){
        activity = app_context;
        myModel = new MyModel("Hello World");
     }

    @Override
    public registerTextView(TextView tvText){
        this.tvText = tvText;
        tvText.setText(myModel.myString);           
    }
 }

但是,我在其他任何地方都没有在网上看到过这种方法,也无法找到很多信息来支持它是一个很好的 android 设计模式。我也有几个问题,例如:

您应该为每个片段或只是为活动创建一个单独的 ViewModel 吗?

这种方法在配置更改和 Activity 重新创建方面是否表现良好,但会产生另一个类的额外开销? 您可以将上下文投射到您的活动中以启用片段管理器吗?

随着代码变得越来越复杂,这将如何扩展?

在我开始将所有项目转换为 MVVM 之前,有没有人有使用这种设计模式的经验,或者任何人都可以指出一些好的学习材料的方向???

【问题讨论】:

  • 你可以用你的代码做任何你喜欢的事情,没有标准。我个人不使用这种模式;除非我出于某种原因需要它,否则我觉得它只是增加了不必要的抽象。

标签: android design-patterns android-activity mvvm android-fragments


【解决方案1】:

我会尽量发表我的意见。我认为您提供的示例代码没有遵循应用 MVVM(或表示模型。MVVM 起源于表示模型)模式的核心价值。该模式的主要动机之一是使 ViewModel(或 Presentaion Model)成为纯 POJO,以便 ViewModel 允许最大可测试性。我没有读过这本书,但我建议你阅读 Martin Fowler 关于模式的原始文章。我创建了一些示例来演示如何在 Android 开发中应用该模式。如果你有兴趣,可以看看这里 - Album Sample,这是 Martin Fowler 原始专辑示例的 android 翻译,以及 AndroidMVVM,一个最小的演示应用程序。

应用该模式的一种方式是:View(Activity 或 Fragment+layout)、ViewModel、Model(业务模型:持久层、网络等)。通过这种方法,为了回答您的问题,我认为一个片段映射到一个 ViewModel。

模式是为了改进设计。如果应用得当,它将降低复杂性,而不是相反。希望这会有所帮助。

【讨论】:

    【解决方案2】:

    Android MVVM 设计模式

    数据绑定库提供了灵活性和广泛的兼容性——它是一个支持库,因此您可以将它与所有 Android 平台版本(回溯到 Android 2.1)一起使用

    构建环境

    android {
        ....
        dataBinding {
            enabled = true
        }
    }
    

    您可以按照这个link 一步一步地在您的android 项目中应用数据绑定。

    高级指南转到开发者页面Link

    【讨论】:

      【解决方案3】:

      我一直在开发一个用于以 MVVM 模式构建 Android 应用程序的库。您应该在那里找到示例。

      https://github.com/manas-chaudhari/android-mvvm

      核心理念:

      • 每个 XML/View 都必须有一个 ViewModel,尽管多个 XML 可以共享一个 ViewModel
      • 每个 ViewModel 都应该有一个模型。多个 ViewModel 可以共享一个模型
      • 使用数据绑定链接 ViewModel View

      架构相关博文:https://manaschaudhari.com/blog/2016/08/19/rxjava-meets-data-binding-part-3

      【讨论】:

      【解决方案4】:

      我对可用代码进行了一些重构,以获得一些要点,例如如何绑定。


      1。用户模型类
      package com.example.mvvm.model;
      
      public class User {
          private String email;
          private String myPassword;
      
          public User(String email, String password) {
              this.email = email;
              this.myPassword = password;
          }
      
          public void setEmail(String email) {
              this.email = email;
          }
          public String getEmail() {
              return email;
          }
      
          public void setMyPassword(String myPassword) {
              this.myPassword = myPassword;
          }
          public String getMyPassword() {
              return myPassword;
          }
      }
      
      2。 LoginViewModel 类
      package com.example.mvvm.viewmodels;
      import android.text.TextUtils;
      import android.util.Patterns;
      
      import androidx.databinding.BaseObservable;
      import androidx.databinding.Bindable;
      
      import com.example.mvvm.BR;
      import com.example.mvvm.model.User;
      
      public class LoginViewModel extends BaseObservable {
      
          @Bindable
          private User user = new User("","");
      
          private String successMessage = "Login was successful";
          private String errorMessage = "Email or Password not valid";
      
          @Bindable
          private String toastMessage = null;
      
          public String getToastMessage() {
              return toastMessage;
          }
          private void setToastMessage(String toastMessage) {
      
              this.toastMessage = toastMessage;
              notifyPropertyChanged(BR.toastMessage);
              notifyPropertyChanged(BR.user);
          }
      
          public void setUserEmail(String email) {
              user.setEmail(email);
              notifyPropertyChanged(BR.user);
          }
      
          public void setUserPassword(String password) {
              user.setMyPassword(password);
              notifyPropertyChanged(BR.user);
          }
      
          @Bindable
          public User getUser() {
              return user;
          }
      
          public void onLoginClicked() {
              if (isInputDataValid())
                  setToastMessage(successMessage);
              else
                  setToastMessage(errorMessage);
          }
      
          public boolean isInputDataValid() {
              return !TextUtils.isEmpty(getUser().getEmail()) &&
                 Patterns.EMAIL_ADDRESS.matcher(getUser().getEmail()).matches() &&
                      getUser().getMyPassword().length() > 5;
          }
      }
      
      3。 activity_main.xml
      <?xml version="1.0" encoding="utf-8"?>
      <layout
          xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:bind="http://schemas.android.com/tools">
      
      
          <data>
              <variable
                  name="viewModel"
                  type="com.example.mvvm.viewmodels.LoginViewModel" />
          </data>
      
      
          <ScrollView
              android:layout_width="match_parent"
              android:layout_height="match_parent">
      
              <LinearLayout
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_gravity="center"
                  android:layout_margin="8dp"
                  android:orientation="vertical">
      
                  <EditText
                      android:id="@+id/inEmail"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:hint="Email"
                      android:inputType="textEmailAddress"
                      android:padding="8dp"
                      android:text="@={viewModel.user.email}" />
      
      
                  <EditText
                      android:id="@+id/inPassword"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:hint="Password"
                      android:inputType="textPassword"
                      android:padding="8dp"
                      android:text="@={viewModel.user.myPassword}" />
      
      
                  <Button
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:layout_marginTop="8dp"
                      android:onClick="@{()-> viewModel.onLoginClicked()}"
                      android:text="LOGIN"
                      bind:user="@{viewModel.user}" />
      
      
              </LinearLayout>
      
          </ScrollView>
      
      </layout>
      
      4。 MainActivity 视图类
      package com.example.mvvm.views;
      
      import androidx.appcompat.app.AppCompatActivity;
      import androidx.databinding.BindingAdapter;
      import androidx.databinding.DataBindingUtil;
      
      import android.os.Bundle;
      import android.view.View;
      import android.widget.Toast;
      
      import com.example.mvvm.R;
      import com.example.mvvm.databinding.ActivityMainBinding;
      import com.example.mvvm.model.User;
      import com.example.mvvm.viewmodels.LoginViewModel;
      
      import java.sql.Time;
      
      public class MainActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
              activityMainBinding.setViewModel(new LoginViewModel());
              activityMainBinding.executePendingBindings();
              activityMainBinding.setViewModel(new LoginViewModel());
              activityMainBinding.inEmail.setText("example@gmail.com");
              activityMainBinding.inPassword.setText("password");
      
          }
      
          @BindingAdapter({"user"})
          public static void runtest(View view, User user) {
              if (user.getEmail() != null)
                  Toast.makeText(view.getContext(), user.getEmail(), Toast.LENGTH_SHORT).show();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        • 2014-04-08
        • 2013-11-24
        相关资源
        最近更新 更多