MVVM(Model - View - ViewModel)最初是在2005年由微软提出的一个UI框架的概念。相比MVP模式,MVVM将Presenter改为了ViewModel,同时实现的View和ViewModel的双向数据绑定,View层的变化会自动导致ViewModel发生变化,ViewModel的数据发生变化也会自动实现View的刷新,开发者可以不用直接处理View和数据的更新操作,MVVM框架会完成这一切,MVVM模式不同层关系如下
Data Binding
在Google I/O2015大会上,Android开发团队发布了官方的MVVM支持函数库Data Binding Library,要求,Gradle的版本大于1.5.0-alphal,Android最低版本Android4.0
Databinding 是一个实现数据和UI绑定的框架,是一个实现 MVVM 模式的工具,有了 Data Binding,在Android中也可以很方便的实现MVVM开发模式。
官网
起步
- 配置Gradle
在app/在build.gradle使用如下配置android { ... dataBinding { enabled = true } }
- 数据绑定
使用@{}
语法可以轻松绑定数据<TextView android:text="@{model.userName}"/>
数据绑定
- 布局文件(View)
Data binding 的布局文件与传统布局文件有一点不同。它以一个layout
标签作为根节点,里面是data
标签与view
标签。view
标签的内容就是不使用 Data Binding 时的普通布局文件内容<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="book" type="app.mrquan.databindingdemo.pojo.Book"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{book.name}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(book.price)}"/> </LinearLayout> </layout>
- 数据对象(Model)
public class Book { public String name; public Integer price; public Book(String name, Integer price) { this.name = name; this.price = price; } /** * Constructor * ... */ }
从 Data Binding 的角度看,这两个类是一样的。public class Book { private String name; private Integer price; public Book(String name, Integer price) { this.name = name; this.price = price; } /** * Constructor * getter setter * ... */ }
在前一个类中表达式@{book.name}
用于android:text
访问name
属性,在后一个类中用于访问getName()
方法。 另外,两者都存在,它会优先解析为getName()
方法。 - 绑定数据(ViewModel)
在默认情况下,会基于布局文件生成一个继承于ViewDataBinding
的Binding
类。例如,布局文件叫 main_activity.xml,所以会生成一个 MainActivityBinding 类。这个类包含了布局文件中所有的绑定关系,会根据绑定表达式给布局文件赋值。绑定方式如下@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ActivityMainBinding 类是自动生成的 ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); // 所有的 set 方法也是根据布局中 variable 名称生成的 binding.setBook(new Book("Thinking in JAVA",100)); }
- 表达式语言
data binding提供了大量的表达式方法 链接
事件处理
有两种实现方式:
-
方法引用(Method References)
-
监听绑定(Listener bindings)
方法引用和监听绑定之间的主要区别在于监听器是在绑定数据时创建的,而不是在触发事件时创建的。如果希望在事件触发时解析表达式,则应使用监听绑定
方法引用
事件可以直接绑定到处理函数方法,类似于activity的
android:onClick
. 它的优势在于表达式会在编译时处理,如果函数不存在或者函数签名不对,编译将会报错。方法引用如下public class MyHandler { public void onClick( View view ) { ... } }
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="book" type="app.mrquan.databindingdemo.pojo.Book"/> <variable name="handler" type="app.mrquan.databindingdemo.MyHandler"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="@{book.name}" android:onClick="@{handler::onClick}"/> <!-- 函数调用也可以使用 `.` , 如handler.onClickFriend , 不过已弃用 --> </LinearLayout> </layout>
注:表达式中方法名必须与监听器对象中方法名完全一致。
监听绑定
在监听绑定中,只要返回值与监听器对象的预期返回值相匹配即可。可以使用带有多个参数的lambda表达式,监听绑定如下
public class MyHandler { public void onClickTwo(View view, Book book) { ... } }
<Button android:text="监听绑定" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:onClick="@{(view) -> handler.onClickTwo(view,book)}" />
注:此功能在 Android Gradle Plugin version 2.0 或更新版本上可用.
深入Layout文件
- 导入(Imports)
data 标签内可以有多个 import 标签。可以在布局文件中像使用 Java 一样导入引用<data> <import type="android.view.View"/> </data>
当类名发生冲突时,可以使用 alias<TextView android:text="@{user.lastName}" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
<import type="com.example.real.estate.View" alias="Vista"/>
- includes
引用变量可以传递到任何include
布局中如下<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bind="http://schemas.android.com/apk/res-auto"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/name" bind:user="@{user}"/> <include layout="@layout/contact" bind:user="@{user}"/> </LinearLayout> </layout>
注:name.xml 与 contact.xml 中都需要声明 user 变量。
- Data Binding 进阶
网友评论