MVC、MVP的区别和MVVM设计模式及实例

来源:互联网 发布:淘宝海景房图片怎么做 编辑:程序博客网 时间:2024/05/16 18:12


    MVVM简介                MVC和MVP的区别


可能你使用过 MVP 设计模式来对代码进行解耦, 但是当前谷歌发布 Data Binding 库来更加简化我们的代码 , 也催生了 MVVM 设计模式在 Android 中的引用 . 在 MVP 中, 我们需要 Model 、 View 、 Presenter 三样进行配合使用 , 但是在 View 中 还是会出现大量的类似 ShowLoad 之类的代码 . 而这次的 MVVM 是由 Model , View , ViewModel 进行配合的 . 其中的区别主要在于 ViewModel , Data Binding 的奇妙之处在于可以将 XML 文件与指定的 JAVA 类绑定 , 实现数据自动更新的效果 .下面来看看结构图:





在 MVVM 设计模式中 , 对于 View 中的数据更新操作都是通过 Data Binding 框架实现的 , 在 Model 发生变化时做出反映 .看看效果图:




依然跟 MVP 的实例一样是一个查询 IP 地址归属地的 Demo .


首先需要打开 Data Binding 绑定功能 , 在 APP 的 build.gradle 文件中添加如下部分


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

先来看 XML 文件的变化


<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android">  <data>    <variable        name="viewModel"        type="com.shire.mvvmdemo.viewModel.MainViewModel"        />  </data>  <RelativeLayout      android:layout_width="match_parent"      android:layout_height="match_parent"      android:paddingBottom="@dimen/activity_vertical_margin"      android:paddingLeft="@dimen/activity_horizontal_margin"      android:paddingRight="@dimen/activity_horizontal_margin"      android:paddingTop="@dimen/activity_vertical_margin"      >    <EditText        android:id="@+id/et_ip"        android:layout_width="200dp"        android:layout_height="wrap_content"        android:hint="IP地址"        />    <Button        android:id="@+id/btn_search"        android:layout_width="200dp"        android:layout_height="wrap_content"        android:layout_toEndOf="@id/et_ip"        android:onClick="@{viewModel.search}"        android:text="查询"        />    <TextView        android:id="@+id/tv_msg"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/et_ip"        />    <ProgressBar        android:id="@+id/pb_load"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/btn_search"        android:layout_toStartOf="@id/btn_search"        android:visibility="gone"        style="?android:attr/progressBarStyleSmall"        />  </RelativeLayout></layout>


可以看到 根节点用的是 <layout> 标签 , 并且还出现了一个 <data> 标签 , 在 <data> 标签中还有一个 <variable> 标签 , 在 <variable> 标签中就是我们需要绑定的类以及他的名字 .


这里使用的名字为 viewModel , 绑定的类是 MainViewModel . 至于绑定这个有什么用, 下面会说到 .


再来看看 Activity 文件

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);        binding.setViewModel(new MainViewModel(binding));    }}

你没看错 , 就是只有这几行代码 ! 其中的 ActivityMainBinding 类是 Data Binding 框架为我们自动生成的 , 这与你的 XML 文件名字相关 , 比如我的 XML 文件名字是 activity_main 那么生成的类就会取消下划线并且在最后加上 Binding 就得到了 ActivityMainBinding . 这个类的实例可以通过 DataBindingUtil.setContentView 来得到 . 这个类里面有我们 XML 文件里所有的控件信息 . 由此 , 也再也不需要去 findViewById 了! 我们先调用了 setViewModel 方法来设置 ViewModel 并且传进去了这个 Binding , 然后我们进入这个 ViewModel 来看看吧 . 界面上的管理目前基本可以全部转移到 ViewModel 中了.

public class MainViewModel implements onSearchListener {  private ActivityMainBinding binding;  private SearchModel searchModel = new SearchModel();  private Handler handler;  public MainViewModel(ActivityMainBinding binding) {    this.binding = binding;    handler = new Handler(Looper.getMainLooper());  }  public void search(View view) {    binding.pbLoad.setVisibility(View.VISIBLE);    searchModel.getIPaddressInfo(binding.etIp.getText().toString().trim(), this);  }  @Override public void onSuccess(final IPAddress ipAddress) {    handler.post(new Runnable() {      @Override public void run() {        binding.pbLoad.setVisibility(View.GONE);        binding.tvMsg.setText(ipAddress.toString());      }    });  }  @Override public void onError() {    handler.post(new Runnable() {      @Override public void run() {        binding.pbLoad.setVisibility(View.GONE);        binding.tvMsg.setText("查询失败");      }    });  }}


构造方法中我们初始化了两个类 Handler 和 ActivityMainBinding , 其中 handler 用于子线程操作完成后更新主线程 UI , ActivityMainBinding 用于操作 View 控件 .


主要看看 search 方法 . 这个方法在 XML 文件中有被绑定到按钮上 , 没注意的可以上去看看 .


binding.pbLoad.setVisibility(View.VISIBLE);

这个就能实现加载动画的显示了! 很方便吧 不需要 findViewById , 然后就是调用 Model 的方法获取需要的信息 , 这里传入了文本编辑框的内容


searchModel.getIPaddressInfo(binding.etIp.getText().toString().trim(), this);


同样的 binding.etIp.getText() 就能拿到内容了 , 各种方便有木有 .


后面拿到了结果之后就通过接口回调对 View 进行了更新 .


@Override public void onSuccess(final IPAddress ipAddress) {    handler.post(new Runnable() {      @Override public void run() {        binding.pbLoad.setVisibility(View.GONE);        binding.tvMsg.setText(ipAddress.toString());      }    });  }




原创粉丝点击