原文:MVVM Light Toolkit使用指南

原文地址:  https://blog.csdn.net/ldld1717/article/details/77040077

概述

MVVM Light Toolkit是一个Android MVVM 轻量级工具库,主要目的是更快捷方便的构建Android MVVM应用程序,工具库添加了一些Data Binding 不支持的属性,还有添加对控件事件的封装,同时提个一个全局消息通道方便ViewModel 之间的通信,Toolkit主要包括两部分Binding和Messenger,接下来,我们分别说明下这两个模块的作用和使用方法。

源码:
Github:https://github.com/Kelin-Hong/MVVMLight

compile 'com.kelin.mvvmlight:library:1.0.0'

Binding


MVVM Binding Schematic Diagram

由上图我们可以看到,在View和ViewModel的绑定中,包含两种绑定,一种是数据的绑定(比如:TextView:text),另外一种命令绑定,命令绑定我们可以理解为事件绑定,(比如:Button:click),但是目前Databinding 并不完全支持命令的绑定, 而且对Data的绑定的支持也不完善(比如说不支持AdapterView对DataSource的绑定),那么在MVVM LightBinding我们添加了部分Data绑定支持和Command绑定的支持。

  • Data 绑定
    我们添加了(ImageView:uri、placeholderImageRes),(ListView:views、itemView) 等部分控件的一些属性,这使得我们用起来就方便很多,例如我们只要在xml布局<ImageView>标签中设置uri,那么这个图片就能自动去加载这个uri的图片,如下:

    <ImageView      android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_alignParentRight="true"       bind:uri="@{viewModel.imageUrl}"  bind:placeholderImageRes="@{R.drawable.ic_launcher}"/>

    当然ImageView还支持其他属性

    placeholderImageRes :图片还没有下载完成时的替换图片
    request_width : 请求图片的宽度,会自动帮你裁剪
    request_height:请求图片的高度,会自动帮你裁剪

接下来看下示例:


image.gif

对于ListView、RecyclerView 和 ViewPager 等AdapterView使用起来就更加简单了,在布局文件添加bind:itemView(子布局模板),bind:items(数据源)还有bind:layoutManager就能ok了,完全不需要写Adapter相关的东西。

  <android.support.v7.widget.RecyclerView        android:layout_width="match_parent"         android:layout_height="match_parent"         bind:itemView="@{viewModel.itemView}"         bind:items="@{viewModel.itemViewModel}"         bind:layoutManager="@{LayoutManagers.linear()}"

然后Java 代码中在ViewModel定义itemView和itemViewModel就可以了列表就能展示出来了

public final ObservableList<ViewModel>  itemViewModel = new  ObservableArrayList<>();  public final ItemView itemView = ItemView.of(BR.viewModel, R.layout.layoutitem_list_view);

动画示例:


listview_databinding.gif

关于AdapterView 数据源绑定问题主要还是Google的DataBinding框架还不够完善,相信不久后肯定有更好的方案出来,让我们更加方便把数据源和布局模板绑定到ListView上,当然现在也有一些开源库帮我们把这个部分做好了,我们也不重复造轮子,就直接使用了关于AdapterView的一些数据绑定扩展,https://github.com/evant/binding-collection-adapter 给了比较详细的描述,基本能满足大部分AdapterView的需求。

接下来列举目前MVVM Light 工具库支持的一些Data Binding的属性:

  • ImageView

    <attr name="uri" /> <!--width for ResizeOptions (use Fresco to load bitmap). --> <attr name="request_width" format="integer" /> <!--height for ResizeOptions (use Fresco to load bitmap). --> <attr name="request_height" format="integer" /> <attr name="placeholderImageRes" format="reference|color" />
  • ListViewViewPagerRecyclerView

     <!-- require ItemView  or  ItemViewSelector   -->  <attr name="itemView" />  <!-- require List<ViewModel> bind to ItemView to presentation.-->   <attr name="items" />  <!-- require a adapter which type of BindingRecyclerViewAdapter<T> to AdapterView-->  <attr name="adapter" />  <attr name="dropDownItemView" format="reference" />  <attr name="itemIds" format="reference" />  <attr name="itemIsEnabled" format="reference" />  <!-- require PageTitles<T>-->  <attr name="pageTitles" format="reference" />
  • ViewGroup

     <!-- require ItemView  or ItemViewSelector -->  <attr name="itemView" />  <!-- require List<ViewModel> bind to ItemView to presentation.-->  <attr name="viewModels" format="reference" />
  • EditText

     <!-- require boolean value to decide whether requestFocus for view. -->  <attr name="requestFocus"  format="boolean" />
  • SimpleDraweeView

     <!-- require String to load Image"-->  <attr name="uri" />
  • WebView

     <!-- require String render to html show in webview-->  <attr name="render" format="string" />

目前整理的一些常用属性和控件可能不足,我们也不太可能能把所有可用的控件和控件关联的属性全部做一些封装,希望开发者自己可以在需要的时候去继承相应的类扩展更多的属性。

  • Command 绑定
    Command 翻译为命令,就是控件发号施令,然后有人去回复处理这个命令,比如Button 发出一个Click Command,那么应该有个处理者来处理这个命令,我们把这个处理者叫做ReplyCommand,我们把ReplyCommand绑定到相应的控件上,如果控件发出Event的时候,就会找到这个ReplyCommand让它来处理这个事件,说得简单一些就是我们对控件一些事件做了简单的封装,使得处理这些事件我们只有关注我们相应事件传递给我们想要的数据,其他UI相关的逻辑并不需要我们去关心。接下来我们简要说明具体使用方法:

       <android.support.v7.widget.RecyclerView           android:id="@+id/recyclerView"           android:layout_width="match_parent"           android:layout_height="match_parent"           bind:onLoadMoreCommand="@{viewModel.loadMoreCommand}"/>

    bind:onLoadMoreCommand: RecyclerView 在滑到最底部的时候自动触发这个事件,这个事件的处理者是一个ReplyCommand<Integer>类型的变量

    接下来我们在ViewModel 里面的定义一个ReplyCommand<Integer> 变量

     public final ReplyCommand<Integer> loadMoreCommand = new ReplyCommand<>(   (count) -> {       /*count 代表当前RecyclerView 有多少个Item,通过这个值我们可以         得到当前应该去加载第几页的数据*/        int page=count / LIMIT;        loadData(page)   });

    对于处理RecyclerView 下拉加载更多,我们之前的做法可能需要去写各种代码来判断是否滑动底部,在OnScrollListener 里面做一些计算然后才知道滑到底部了,但是如果用封装好的Command事件,你的ViewModel里面的代码将非常简洁,只要简要的声明一个 ReplyCommand<Integer>,它就能自动传一个当前List中Item的总数给你,你要做的只是专注你的业务处理(比如 加载数据),ViewModel 里面只处理数据,不处理控件,没有任何控件的引用,所以UI的状态和变化都由数据来绑定控制的,这样数据就成了主角,我们在ViewModel 里面只要和数据打交道就可以了。


动画示例:


listview load more

同时对于我最常见的点击事件,我们也做对了click事件的封装,封装成一个clickCommand,接受的参数是一个无参的ReplyCommand:


动画示例:


clickCommand.gif

关于下拉刷新控件SwipeRefreshLayout的下拉刷新事件也简单封装成另一个ReplyCommand

动画示例:


refresh.gif

接下来列举目前MVVM Light 工具库支持的一些Command Binding的属性:

  • View

    <!-- require ReplyCommand to deal with view click event. --> <attr name="clickCommand" format="reference" /> <!-- require ReplyCommand<Boolean> to deal with view focus change event.  ReplyCommand would has params which means if view hasFocus.--> <attr name="onFocusChangeCommand" format="reference" /> <!-- require ReplyCommand<MotionEvent> --> <attr name="onTouchCommand" />
  • ListViewRecyclerView

    <!-- require ReplyCommand<Integer> --> <attr name="onScrollStateChangedCommand" /> <!-- require ReplyCommand<ListViewScrollDataWrapper> -->   <attr name="onScrollChangeCommand" /> <!-- require ReplyCommand<Integer> count of list items--> <attr name="onLoadMoreCommand" format="reference" />
  • ViewPager

     <!--require ReplyCommand<ViewPagerDataWrapper> --> <attr name="onPageScrolledCommand" format="reference" />   <!--require ReplyCommand<Integer> --> <attr name="onPageSelectedCommand" format="reference" /> <!--require ReplyCommand<Integer> --> <attr name="onPageScrollStateChangedCommand" format="reference" />
  • EditText

    <!--require ReplyCommand<TextChangeDataWrapper> --> <attr name="beforeTextChangedCommand" format="reference" /> <!--require ReplyCommand<TextChangeDataWrapper> -->         <attr name="onTextChangedCommand" format="reference" />  <!--require ReplyCommand<String> -->  <attr name="afterTextChangedCommand" format="reference" />
  • ImageView

     <!--  require ReplyCommand<Bitmap> -->  <attr name="onSuccessCommand" format="reference" />  <!--require ReplyCommand<CloseableReference<CloseableImage>> -->  <attr name="onFailureCommand" format="reference" />
  • ScrollViewNestedScrollView

    <!-- require ReplyCommand<ScrollDataWrapper> --> <attr name="onScrollChangeCommand" /> <!-- require ReplyCommand<NestScrollDataWrapper> --> <attr name="onScrollChangeCommand" />
  • SwipeRefreshLayout

    <!-- require RelayCommand<> --> <attr name="onRefreshCommand" format="reference" />

    以上的Command有继承效应,即ImageView、TextView是View的子类,所以它们都拥有View 扩展的Data Binding和Command Binding 如:clickCommand 等。

注:

  • MVVMLight 目前只支持上面提及的部分的控件Data和Command绑定,还有大部分的控件一些属性和事件并没有去封装,我们希望您根据自己的需求去补充,包括一些你用的自定义控件和第三方控件,都可以简单封装成一个Command,这样使得我们的ViewModel 更加简洁同时是我们更能专心处理数据和业务,不关心控件和UI。
  • 上面涉及的属性和Command,我们在attrs文件都已经声明,您在xml文件使用中将可以自动提示相应的名称,比如你在TextView中打bind:的时候和TextView相关的属性都会提示(如:requestFocus、clickCommand、等相关的属性),但是属性后面需要哪种ReplyCommand<T>,即T应该是什么类型,就需要查一下相应的文档、或者查一下源码。
  • 由于没办法做到在xml输入属性(如bind:clickCommand)自动提示应该输入什么值接入什么参数,所以这时候最简单的方式就是去查源码,我们把每个控件都单独放到一个包里面,方便查找源码。如果你没找到源码的位置,你可以shift+command+o 然后输入ViewBindingAdapter(也就是打开文件ViewBindingAdapter.class 或者 ViewBindingAdapter.java )然后选择相应的控件,去查看该控件的支持哪些属性和Command同时可以查看需要的ReplyCommand的类型。
  • 虽然是ViewBindingAdapter 里面的方法是static,但是是支持重写的,保持参数和@BindingAdapter(value =*) 的值不变,DataBinding 的找方法的时候就优先采用你写的方法,而不是库里的方法,也就是如果你对ViewBindingAdapter的里面的static方法的实现不满意的是可以重写的。

Messenger

引入messenger最主要的目的就实现ViewModel和ViewModel的通信,也可以用做View和ViewModel的通信,但是并不推荐这样做。ViewModel主要是用来处理业务和数据的,每个ViewModel都有相应的业务职责,但是在业务复杂的情况下,可能存在交叉业务,这时候就需要ViewModel和ViewModel交换数据和通信,这时候一个全局的消息通道就很重要的。接下来我们简单看一下messenger的使用:

  • 全局广播消息,没有参数
       /* 全局发送一个消息,但是不传任何参数给接收者   TOKEN: 相当于broadcast的Action,谁注册了这个令牌,相当于准备接收这个消息*/   Messenger.Default().sendNoMsg(TOKEN);    /* context: 一般是activity,代表接收者,用于在取消注册的时候使用unRegister(context)可快速取消这个context里面的所有注册       TOKEN: 相当于broadcast的Action,谁注册了这个令牌,相当于准备接收这个消息       (data)->{ }: 处理消息的Action */    Messenger.Default().register(context, TOKEN, () -> { });
  • 全局广播消息,带有参数
     /*发送消息,传递参数data(任何类型都可),TOKEN 是一个令牌(String类型)相当于   broadcast的Action,谁注册了这个令牌,相当于准备接收这个消息*/  Messenger.getDefault().send(data, TOKEN)   /*  context: 同上    * TOKEN: 相当于broadcast的Action,谁注册了这个令牌,相当于准备接收这个消息    * Data.class: 传递过来参数的类型(如 String.class,Model.class)    * (data)->{ }: 处理消息的function,参数是传递过来的 */  Messenger.getDefault().register(context, TOKEN, Data.class, (data) -> { });

示例:



  • 发送到指定的接收器(不常用)
     /*target 代表接收对象,一般是Activity(ViewModel 持有Activity的引    用),直接将消息发到指定的目标,而不是广播*/ Messenger.getDefault().sendToTarget(T message, R target) Messenger.getDefault().sendNoMsgToTargetWithToken(Object token,R target) Messenger.getDefault().sendNoMsgToTarget(Object target)
  • 取消注册

    /*一般在Activity的OnDestroy()方法中调用就可以, 因为我们一般注册的时候, 第一个参数   recipient就是传的当前的context,所以只要取消注册,这个Activity就再也收不到任何的消息了*/  Messenger.getDefault().unregister(Object recipient)"

    Messenger在全局虽然传递数据和通知非常方便,但是建议不要滥用,消息通知太多也意味着耦合性太高,代码框架设计不够友好,同时影响代码的可读性,ViewModel和View最好是用绑定的方式去处理UI和事件,ViewModel 和ViewModel 一些数据的通信交互才用Messenger来传递会好一些。

    注:

    1、Messenger 一定要取消注册,不然会造成严重的内存泄露
    2、Messenger 的TOKEN在命名的时候要注意,最好和相关的ViewModel结合起来,避免在同一个App出现两个相同的Token,这样会把消息发到其他你不知道的地方,造成潜在的BUG!

MVVM Light Toolkit使用指南的更多相关文章

  1. Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架

    Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架   本章节,我将通过示例介绍如何搭建mvvmlight开发环境.示例中的我会针对wpf ...

  2. MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(导航)

    系列一:看的迷迷糊糊的 一.Mvvm Light Toolkit for wpf/silverlight系列之准备工作 二.Mvvm Light Toolkit for wpf/silverlight ...

  3. How to install MVVM Light Toolkit via NuGet

    Here is how you can install MVVM Light Toolkit  via NuGet in an easy way using only Visual Studio. S ...

  4. Mvvm Light Toolkit 入门

    原文:Mvvm Light Toolkit 入门 前言 之前学习UWP的时候就一直看到有关MVVM的资料但是一直没有系统的去学,最近正好有时间,特地来攻破这个点,顺便学习一下VS与GitHub的链接和 ...

  5. MVVM Light须要注意的10个问题

    MVVM Light须要注意的10个问题 从使用XAML技术基础開始(实际上并非非常久曾经).我便关注MVVM(Model – View – ViewModel)模式.偶然接触到MVVM Light不 ...

  6. MVVM Light 笔记

    4.关于子视图, MVVMLight Using Two Views:http://www.codeproject.com/Articles/323187/MVVMLight-Using-Two-Vi ...

  7. 【MVVM Light】Messager的使用

    一.前言       在MVVM编程的模式中,有时候我们会遇到一个很尴尬的情况: 若干个xaml.cs都复用一个ViewModel,当ViewModel想传递一个特定的消息给某一个xaml.cs的时候 ...

  8. 【MVVM Light】新手初识MVVM,你一看就会

    一.前言 作为一个初入软件业的新手,各种设计模式与框架对我是眼花缭乱的.所以当我接触到这些新知识的时候就希望自己能总结几个步骤,以便更好更方便的在日常工作中进行使用. MVVM顾名思义就是Model- ...

  9. MVVM Light中的Message

    比喻:像漂流瓶一样发送一个Message,任何人有兴趣就可以拾起来. MVVM Light中的Message的使用分为三个步骤: 1.创建一个类,包含要传递的Message. 2.在ViewModel ...

随机推荐

  1. 【Java入门提高篇】Day4 Java中的回调

    又忙了一周,事情差不多解决了,终于有可以继续写我的博客了(各位看官久等了). 这次我们来谈一谈Java里的一个很有意思的东西——回调. 什么叫回调,一本正经的来讲,在计算机程序设计中,回调函数是指通过 ...

  2. iis 发布asp.net mvc 网站时候js css 压缩问题,图片不加载问题

    一.JS CSS 自动压缩问题 默认情况下mvc这个框架会把css,js文件压缩成一个js或者css文件,一会发现只有一个<link href="/Content/css?v=ji3n ...

  3. Log4Net记录到文件

    将这篇文章的配置文件中的log4net节点下的内容替换成下面的 https://www.cnblogs.com/RambleLife/p/9165248.html <log4net debug= ...

  4. [IDEA_1] IDEA 使用指南

    1. IDEA 安装与配置 具体细节待补充... 2. 优化编程体验 2.1.1 新建类后自动添加自定义的注释 在主界面使用快捷键 Ctrl + Alt + S 进入 Settings 页面 依次打开 ...

  5. 树莓派踩坑备忘录 -- 使用 Linux

    目录 一,工欲善其事,必先利其器 二,开机必备 三,更新 apt-get 源与软件搜索 四,安装 .NET Core 五,文件传输 六,搜索与安装软件 七,常见缺少的 xxx.so 八,小技巧与工具 ...

  6. 高斯消去、追赶法 matlab

    1. 分别用Gauss消去法.列主元Gauss消去法.三角分解方法求解方程组 程序: (1)Guess消去法: function x=GaussXQByOrder(A,b) %Gauss消去法 N = ...

  7. 1.1环境的准备(一)之Python解释器的安装

    目录: 1.Python-解释器的下载 2.Python-解释器的安装 3.Python-解释器的测试 4.Python的环境变量的配置 (一)Python解释器的安装: 1.官网:https://w ...

  8. October 20th 2017 Week 42nd Friday

    My life is in these books. Read these and know my heart. 我的人生就在这些书中,读完他们就能读懂我的心. Some people say tha ...

  9. SQLServer 删除表中的重复数据

    create table Student(        ID varchar(10) not null,        Name varchar(10) not null, ); insert in ...

  10. Alpha冲刺报告(4/12)(麻瓜制造者)

    今日完成的情况 江郑: 今天对数据库的需求部分进行了完善 邓弘立: 完成了首页界面UI 刘双玉: 基本完成商品信息发布接口 汪志彬: 尝试UI的设计 符天愉: 将登录接口部署到服务器上,结果Linux ...