美文网首页
Android 官方架构组件-数据绑定DataBinding

Android 官方架构组件-数据绑定DataBinding

作者: R7_Perfect | 来源:发表于2019-10-25 15:41 被阅读0次

    环境运行要求 Android 4.0 (API level 14)及以上
    Android Gradle插件要求1.5.0及以上

    将dataBinding元素添加App的build.gradle文件中

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

    在AndroidSutdio的布局编辑窗口,例如,以下示例中声明的TextView小部件上显示my_default值:

    <TextView android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{user.firstName, default=my_default}"/>
    

    官方例子

    布局和绑定表达式

    数据绑定布局文件略有不同,它们以layout的根标记开始,后跟一个数据元素和一个视图根元素。 此视图元素是您的根将位于非绑定布局文件中的元素。 以下代码显示了一个示例布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="user" type="com.example.User"/>
       </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="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>
    

    数据中的user变量描述了可以在此布局中使用的属性。

    <variable name="user" type="com.example.User" />
    

    使用“ @ {}”语法将布局内的表达式写入属性属性中。 在这里,TextView文本设置为用户变量的firstName属性:

    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@{user.firstName}" />
    

    让我们来看看User类的定义

    data class User(val firstName: String, val lastName: String)
    

    这种数据为只读,通常只取一次,后面不会再取
    用于android:text属性的表达式@ {user.firstName}用于访问前一类中的firstName字段和后一类中的getFirstName()方法

    绑定数据

    程序会自动为每个布局文件生成一个绑定类。 默认情况下,类的名称基于布局文件的名称,将其转换为Pascal大小写并向其添加Binding后缀。 上面的布局文件名是activity_main.xml,因此相应的生成类是ActivityMainBinding。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(
                this, R.layout.activity_main)
    
        binding.user = User("Test", "User")
    }
    

    或者,可以使用LayoutInflater获取视图,如以下示例所示:

    val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
    

    如果在Fragment,ListView或RecyclerView适配器中使用数据绑定项,如以下代码示例所示

    val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
    // or
    val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
    

    表达式

    + - / * %
    String +
    && ||
    & | ^
    + - ! ~
    >> >>> <<
    == > < >= <= (注意 < 需要转为 <)
    instanceof
    Grouping ()
    Literals - character, String, numeric, null
    Cast
    Method calls
    Field access
    []
    ?:

    例子:

    android:text="@{String.valueOf(index + 1)}"
    android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
    android:transitionName='@{"image_" + id}'
    
    不能使用的关键字:

    this
    super
    new
    泛型调用

    空操作:

    空合并操作符(??)如果不为空,则选择左操作数;如果前一个为空,则选择右操作数。

    android:text="@{user.displayName ?? user.lastName}"
    相当于
    android:text="@{user.displayName != null ? user.displayName : user.lastName}"
    

    属性

    避免空指针

    生成的数据绑定代码自动避免空指针异常。 例如,在表达式@ {user.name}中,如果user为null,则为user.name分配其默认值null。 如果您引用user.age,age是int类型,则数据绑定将使用默认值0。

    集合

    使用[]运算符访问常见的集合,例如数组,列表,稀疏列表和映射。

    <data>
        <import type="android.util.SparseArray"/>
        <import type="java.util.Map"/>
        <import type="java.util.List"/>
        <variable name="list" type="List&lt;String>"/>
        <variable name="sparse" type="SparseArray&lt;String>"/>
        <variable name="map" type="Map&lt;String, String>"/>
        <variable name="index" type="int"/>
        <variable name="key" type="String"/>
    </data>
    …
    android:text="@{list[index]}"
    …
    android:text="@{sparse[index]}"
    …
    android:text="@{map[key]}"
    

    上面例子中的 @{map[key]}可以写成@{map.key}

    String

    您使用单引号将属性值引起来,这样可以在表达式中使用双引号,如以下示例所示:

    android:text='@{map["firstName"]}'
    或者
    android:text="@{map[`firstName`]}"
    
    Resource资源

    示例

    android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
    

    String格式和复数可以这样写:

    android:text="@{@string/nameFormat(firstName, lastName)}"
    android:text="@{@plurals/banana(bananaCount)}"
    
    //复数形式
      Have an orange
      Have %d oranges
    
    android:text="@{@plurals/orange(orangeCount, orangeCount)}"
    

    事件处理

    可以通过定义接口,定义事件处理,但是部分关键接口名和系统不能冲突:
    android:onClick
    android:onSearchClick
    android:onZoomIn
    android:onZoomOut

    有两种方式:

    方式一 直接绑定

    事件可以直接绑定到处理程序方法,类似于可以将android:onClick分配给活动中的方法的方式。 与View onClick属性相比,一个主要优点是表达式是在编译时处理的,因此,如果该方法不存在或其签名不正确,则会收到编译时错误。
    和Listener绑定之间的主要区别在于,实际的Listener实现是在绑定数据时创建的,而不是在事件触发时创建的。

    class MyHandlers {
        fun onClickFriend(view: View) { ... }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="handlers" type="com.example.MyHandlers"/>
           <variable name="user" type="com.example.User"/>
       </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="@{user.firstName}"
               android:onClick="@{handlers::onClickFriend}"/>
       </LinearLayout>
    </layout>
    
    方式二 Listener绑定
    class Presenter {
        fun onSaveClick(task: Task){}
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable name="task" type="com.android.example.Task" />
            <variable name="presenter" type="com.android.example.Presenter" />
        </data>
        <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
            <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.onSaveClick(task)}" />
        </LinearLayout>
    </layout>
    

    使用回调时,databinding将自动创建必要的Listener并将其注册为事件。 当View触发事件时,databinding将传递给方法。
    上述方法也可以这样写

    android:onClick="@{(view) -> presenter.onSaveClick(task)}"
    

    如果想用view回调:

    class Presenter {
        fun onSaveClick(view: View, task: Task){}
    }
    
    android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
    

    lambda表达式

    class Presenter {
        fun onCompletedChanged(task: Task, completed: Boolean){}
    }
    
    <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
    

    如果事件返回值不是为void,则表达式也必须返回相同类型的值:

    class Presenter {
        fun onLongClick(view: View, task: Task): Boolean { }
    }
    
    android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
    

    android:onLongClick返回值为bool型,所以表达式也为bool值
    如果由于空对象而无法对表达式求值,则数据绑定将返回该类型的默认值。

    android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"
    

    Imports, variables, and includes

    databinding库提供了一些功能,例如导入,变量和包含。 Imports可以轻松引用布局文件中的类。 variables能够描述可在绑定表达式中使用的属性。includes在整个应用程序中重复使用复杂的布局。

    Imports
    <data>
        <import type="android.view.View"/>
    </data>
    

    导入View类可以从绑定表达式中引用它。 下面的示例演示如何引用View类的VISIBLE和GONE常量:

    <TextView
       android:text="@{user.lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
    

    类型别名
    当类名冲突时,可以将其中一个类重命名为别名。 下面的示例将com.example.real.estate包中的View类重命名为Vista:

    <import type="android.view.View"/>
    <import type="com.example.real.estate.View"
            alias="Vista"/>
    

    使用Vista来引用com.example.real.estate.View,并且可以使用View来引用布局文件中的android.view.View

    导入其他类
    导入的类型可用作变量和表达式中的类型引用。 下面的示例显示将User和List用作变量的类型:

    <data>
        <import type="com.example.User"/>
        <import type="java.util.List"/>
        <variable name="user" type="User"/>
        <variable name="userList" type="List&lt;User>"/>
    </data>
    

    强转:

    <TextView
       android:text="@{((User)(user.connection)).lastName}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    

    引用
    当在表达式中引用静态字段和方法时,也可以使用导入的类型。 以下代码导入MyStringUtils类并引用其大写方法:

    <data>
        <import type="com.example.MyStringUtils"/>
        <variable name="user" type="com.example.User"/>
    </data>
    …
    <TextView
       android:text="@{MyStringUtils.capitalize(user.lastName)}"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    Variables

    使用多个变量,每个变量描述可以在布局上设置的属性,以在布局文件内的绑定表达式中使用。 以下示例声明用户,图像和注释变量:

    <data>
        <import type="android.graphics.drawable.Drawable"/>
        <variable name="user" type="com.example.User"/>
        <variable name="image" type="Drawable"/>
        <variable name="note" type="String"/>
    </data>
    

    在编译时检查变量类型,因此,如果变量实现Observable或是Observable集合,则应在类型中反映出来。 如果变量是未实现Observable接口的基类或接口,则不会观察到变量。

    当针对各种配置(例如,横向或纵向)有不同的布局文件时,将合并变量。 这些布局文件之间不得有冲突的变量定义。

    对于每个所描述的变量,生成的绑定类都有一个setter和getter。 变量将使用默认的托管代码值,直到调用setter为止-引用类型为null,int为0,布尔值为false,等等。

    会根据需要生成一个特殊的名为context的变量,用于绑定表达式。 context的值是根视图的getContext()方法中的Context对象。 上下文变量被具有该名称的显式变量声明覆盖。

    Includes

    以下示例显示了name.xml和contact.xml布局文件中包含的用户变量:

    <?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>
    

    数据绑定不支持包含作为merge元素的直接子级。 例如,不支持以下布局:

    <?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>
       <merge><!-- Doesn't work -->
           <include layout="@layout/name"
               bind:user="@{user}"/>
           <include layout="@layout/contact"
               bind:user="@{user}"/>
       </merge>
    </layout>
    

    相关文章

      网友评论

          本文标题:Android 官方架构组件-数据绑定DataBinding

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