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


    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());
      }
    });
  }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值