jetpack之数据绑定, DataBinding(一)简单形式

在这里,实现android 的数据绑定,是依靠Data Binding library库实现的。目的是将数据的交互由activity移动到layout布局文件和专门的数据类中,从而做到更好的封装。初学jetpack包,其实是抱着偷懒的心理来的。一开始感觉,这个databing 与 srping boot 当中mybbits很是想像,解决的问题也是数据展示与数据处理分离。想让布局的数据随着数据对象的变化自动变化。

现在就文档上介绍的三种方法来交流下个人在使用的心得。其实这三种数据绑定方法,分别是由浅入深的,数据类型从刚开始的初始类型,到可观察的初始类型,再可观察的初始类型及其容器,最后是整个可观察的类,实现自行更新ui,数据逻辑。开始走起!

一、最简单形式

layout —— 数据类  —— activity

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

其中表达式是@{}, 数据是在data标签内,并表明了数据variable变量的名字,你可以下方面的控件中引用对象的名字,类型,你定义的数据类。在data标签里还可以import,导入资源,像这样。

<import type="com.example.android.databinding.basicsample.R"/>
        <import type="com.example.android.databinding.basicsample.util.ConverterUtil"/>
        <variable
            name="user"
            type="com.example.android.databinding.basicsample.data.ObservableFieldProfile" />

这样,你声明的variable,和import来的资源,软件包,都可以在下面的布局控件中在@{}表达中使用,还有它也有一个default可以让你指定默认值, 这个要用``包住,数字键1前面的那个键。表示是个常量。

数据类:

public class User {
  public final String firstName;
  public final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

final修饰符表示,这个类型数据,程序只能用读,数据不变的。

activity这样的在onCreate方法中:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
   User user = new User("Test", "User");
   binding.setUser(user);
}

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());

是从运行是获那个绑定对象。ActivityMainBinding 这是一个根据layout文件名称生成的生成类,以Binding为后缀。

这三者里面,在layout文件中要使用的表达式,很强大,支持下下运算,见识下:

一类跟java代码中相似的运算符:

Mathematical + - / * %
String concatenation +
Logical && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <= (Note that < needs to be escaped as &lt;)
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:

而不能使用类似java中的this, supper, new, 或直接代码调用。

支持??空联合运算 ,可以看作?:的缩写,不为空选择前面,空时选择后面值。

android:text="@{user.displayName ?? user.lastName}"

还支持,对象属性引用,只是注意空指针引用,那会引发异常。

android:text="@{user.lastName}"

更支持,集合运算[]

<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来代替。

注意,如果双引号要用字符串字面量,则要用键盘数字1前面那个符号,叫后引号。又或者字面量用双引号,而外层用单引号。

表达内,还可以引用资源:

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

支持还支持string.xml里面格式化字符串,像这样

<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

你需要传参数:

android:text="@{@string/welcome_messages(firstName, 50)}"

还少用的字符串复数形式:

 <plurals name="numberOfSongsAvailable">
        <!--
             As a developer, you should always supply "one" and "other"
             strings. Your translators will know which strings are actually
             needed for their language. Always include %d in "one" because
             translators will need to use %d for languages where "one"
             doesn't mean 1 (as explained above).
          -->
        <item quantity="one">%d song found.</item>
        <item quantity="other">%d songs found.</item>
    </plurals>

也记要传参.

还有一些资源引用时,表达式内要明确求值格式,这些是:

某些资源引用需要明确求值的表达格式
TypeNormal referenceExpression reference
String[]@array@stringArray
int[]@array@intArray
TypedArray@array@typedArray
Animator@animator@animator
StateListAnimator@animator@stateListAnimator
color int@color@color
ColorStateList@color@colorStateList
   
   
   
   
   
   
   
   

以是在表示式里求值,赋给控件属性,控件的属性中除了值,还有一种是事件处理器。当控件的事件被触发后,要调用相应的处理代码,这个我们提供并设定。databing 库为我们提供了两方法来实现,方法引用和事件绑定。

一是通过方法引用。我们不仅可以将数据对象绑定到layout当中,还可以将一个用于处理事件的类,也放到layout的data标签中去。然后在控件的响应事件处引用我们处理事件类中的方法。比如:

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

许多控件都onClick,控件的事件也会传递,注意引起冲突的地方。其中一些特别的如:

 

ClassListener setterAttribute 
ZoomControlssetOnZoomInClickListener(View.OnClickListener)android:onZoomIn 
ZoomControlssetOnZoomOutClickListener(View.OnClickListener)android:onZoomOut 
    
SearchViewsetOnSearchClickListener(View.OnClickListener)android:onSearchClick 
    
    
    

第二方法,处理方法,绑定事件侦听器。如示:

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

需要我们定义那个侦听器:

public class Presenter {
    public void onSaveClick(Task task){}
}

当表达中有了这么一个回调监听器的指定,数据绑定模块会自动产生侦听器实例,并把它注册到事件流当中来。这里侦听器,可以给它传参,也可以不传,还可以确定返回值。不过,值得注意的是避免空值。

如果你需要一个带指示的表达式,可以这样:

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

尽管表达式地很强大,但不要滥用,使用代码阅读困难,应该很简单,只像是从ui到从到你的回调,你应该实现回调代码内的业务逻辑,以便表达内用到它实现相应的功能。

最后,再补充下import 和 include,它们有效地扩展了数据的能力范围。

import有点像代码的中导入到当前空间一样,只是为了避免名字冲突你还可以使用别名,如:

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

除了导入系统的类,也可以是自己的类,并可以作为引用数据的数据类型,如:

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

引入地类可以作为强型转换,也可有表达式内引用它的静态成员。作为管理代码的一部分,java.lang.*是自动导入的。

在data标签中的变量variable可以有多个条目,要标明name,type,如:

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

注意此处类型会编译时侦测,类型是实现了ObservableObservable collection的类型,还要注意不同的layout配置文件相同变量名合并时冲突问题,都是要避免的。根据layout文件自动生成的绑定类,对变量有一对setter,getter有其缺省值,引用型为null,int为0, boolean为false等,但一个很特别的变量名,context,它是从根View的getContext()方法中得到Context对象,它会覆盖你明确定义的context.

接下来是include,将别处layout引用变量的表达式,引入到当前声明变量的layout当中。如:

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

总结:这里首先是介绍了简单数据绑定,重点是表达使用,引入,导入。特点是表达式内容较大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值