Android架构模式-MVVM-DataBinding

作者: quanCN | 来源:发表于2019-07-06 22:02 被阅读85次

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
         * ...
         */
    }
    
    public class Book {
        private String name;
        private Integer price;
    
        public Book(String name, Integer price) {
            this.name = name;
            this.price = price;
        }
        /**
         * Constructor
         * getter setter
         * ...
         */
    }
    
    从 Data Binding 的角度看,这两个类是一样的。
    在前一个类中表达式 @{book.name} 用于 android:text 访问 name 属性,在后一个类中用于访问 getName() 方法。 另外,两者都存在,它会优先解析为 getName() 方法。
  • 绑定数据(ViewModel)
    在默认情况下,会基于布局文件生成一个继承于ViewDataBindingBinding 类。例如,布局文件叫 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>
    
    <TextView
       android:text="@{user.lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
    
    当类名发生冲突时,可以使用 alias
    <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 进阶

相关文章

网友评论

    本文标题:Android架构模式-MVVM-DataBinding

    本文链接:https://www.haomeiwen.com/subject/pygmhctx.html