文档章节

Android官方数据绑定框架DataBinding(二)

i
 i_love_lu
发布于 2016/03/04 10:41
字数 2254
阅读 421
收藏 0

六、 表达式 
短暂的幸福时光,我们还是要告别java代码了,继续回到xml中,这一块,我们来学习一下表达式,什么?这玩意在xml中还支持表达式!

<TextView  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:text='@{error ? "error" : "ok"}'/>

还记得上面我们定义了一个boolean的变量没有用到,这里我们就用到了,看好android:text,这里是一个三元表达式,如果error是true,则text就是error,否则是ok。这里还支持null合并操作,什么是null合并,相信看一眼你就知道了

android:text='@{str==null ?? "not null"}'

简单解释一下,如果str是null,text的值就是str本身,否则就是”not null”。 
它还支持一下表达式:

  • Mathematical + - / * %

  • String concatenation +

  • Logical && ||

  • Binary & | ^

  • Unary + - ! ~

  • Shift >> >>> <<

  • Comparison == > < >= <=

  • instanceof

  • Grouping ()

  • Literals - character, String, numeric, null

  • Cast

  • Method calls

  • Field access

  • Array access []

  • Ternary operator ?:

但是它不支持一下表达式:

  • this

  • super

  • new

  • Explicit generic invocation

七、 其他遗漏点 
说到这里,xml中的事情基本算完了,但是还有几个小地方没有说,顺便说一下。 
1. 设置别名 
假如我们import了两个相同名称的类咋办?别怕,别名来拯救你!例如:

...  
<data>  
  <import type="xxx.Name" alias="MyName">  
  <import type="xxx.xx.Name">  
</data>  
<TextView xxx:@{MyName.getName()}>  
<TextView xxx:@{Name.getName()}>  
...

自定义Binding名称 
还记得系统为我们生成好的那个binding类名吗?如果只能使用那样的是不是有点太暴力了?好在google对我们还算友好了,允许我们自定义binding名称,定制名称也很简单,就是给data一个class字段就ok。 
例如:

<data class=".Custom">...</data>

那么:DataBindingUtils.setContentView返回的binding类就是:你的应用包名.Custom

八、事件绑定 
大家都知道,在xml中我们可以给button设置一个onClick来达到事件的绑定,现在DataBinding也提供了事件绑定,而且不仅仅是button。 
来看一下:

<layout xmlns:android="http://schemas.android.com/apk/res/android">  
    <data>  
        <import type="org.loader.app3.EventHandlers" />  
        <variable  
            name="handlers"  
            type="EventHandlers" />  
    </data>  
  
    <LinearLayout  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:orientation="vertical">  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="CLICK ME"  
            android:onClick="@{handlers.handleClick}"/>  
    </LinearLayout>  
</layout>

定义了一个EventHandlers类型的handlers变量,并在onClick的时候执行EventHandlershandleClick方法。 
继续看看EventHandlers是怎么写的。

public class EventHandlers {  
    public void handleClick(View view) {  
        Toast.makeText(view.getContext(), "you clicked the view", Toast.LENGTH_LONG).show();  
    }  
}

很简单,就是简单的Toast了一下,这里要注意的是,handlerClick方法需要一个View的参数。

九、 数据对象 
我们学会了通过binding为我们的变量设置数据,但是不知道你有没有发现一个问题,当我们数据改变的时候会怎样?数据是跟随着改变呢?还是原来的数据 呢?这里告诉你:很不幸,显示的还是原来的数据?那有没有办法让数据源发生变化后显示的数据也随之发生变化?先来想想ListView是怎么做的, ListView的数据是通过Adapter提供的,当数据发生改变时,我们通过notifyDatasetChanged通过UI去改变数据,这里面的原理其实就是内容观察者,庆幸的是DataBinding也支持内容观察者,而且使用起来也相当方便!

BaseObservable 
我们可以通过Observable的方式去通知UI数据已经改变了,当然了,官方为我们提供了更加简便的方式BaseObservable,我们的实体类只需要继承该类,稍做几个操作,就能轻松实现数据变化的通知。如何使用呢? 首先我们的实体类要继承BaseObservale类,第二步在Getter上使用注解@Bindable,第三步,在Setter里调用方法notifyPropertyChanged,第四步,完成。就是这么简单,下面我们来实际操作一下。 
首先定义一个实体类,并继承BaseObservable

public class Student extends BaseObservable {  
    private String name;  
  
    public Student() {  
    }  
  
    public Student(String name) {  
        this.name = name;  
    }  
  
    @Bindable  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
        notifyPropertyChanged(org.loader.app4.BR.name);  
    }  
}

观察getName方法,我们使用了@Bindable注解,观察setName,我们调用了notifyPropertyChanged方法,这个方法还需要一个参数,这里参数类似于R.java,保存了我们所有变量的引用地址,这里我们使用了name。 
再来看看布局文件。

<layout xmlns:android="http://schemas.android.com/apk/res/android">  
    <data class=".Custom">  
        <import type="org.loader.app4.Student" />  
        <variable  
            name="stu"  
            type="Student"/>  
        <variable  
            name="click"  
            type="org.loader.app4.MainActivity" />  
    </data>  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:onClick="@{click.click}"  
        android:text="@{stu.name}"/>  
</layout>

不多说了,我们给TextView设置了文本,还有点击事件。Activity,

public class MainActivity extends AppCompatActivity {  
  
    private Student mStu;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        org.loader.app4.Custom binding = DataBindingUtil.setContentView(this,  
                R.layout.activity_main);  
        mStu = new Student("loader");  
        binding.setStu(mStu);  
        binding.setClick(this);  
    }  
  
    public void click(View view) {  
        mStu.setName("qibin");  
    }  
}

这段代码,首先显示的是loader,当我们点击TextView时,界面换成qibin。

ObservableFields家族 
上面使用BaseObservable已经非常容易了,但是google工程师还不满足,继续给我们封装了一系列的ObservableFields,这里有ObservableFieldObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable
ObservableFields的使用方法就更加简单了,例如下面代码,

public class People {  
    public ObservableField<String> name = new ObservableField<>();  
    public ObservableInt age = new ObservableInt();  
    public ObservableBoolean isMan = new ObservableBoolean();  
}

很简单,只有三个ObservableField变量,并且没有getter和setter,因为我们不需要getter和setter。 
在xml中怎么使用呢?

<layout xmlns:android="http://schemas.android.com/apk/res/android">  
    <data class=".Custom">  
  
        <variable  
            name="people"  
            type="org.loader.app4.People" />  
    </data>  
    <LinearLayout  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:orientation="vertical">  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="@{people.name}"/>  
  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="@{String.valueOf(people.age)}"/>  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text='@{people.isMan ? "man" : "women"}'/>  
    </LinearLayout>  
</layout>

也很简单,直接使用变量,那怎么赋值和取值呢?这些ObservableField都会有一对getset方法,所以使用起来也很方便了:

...  
mPeople = new People();  
binding.setPeople(mPeople);  
mPeople.name.set("people");  
mPeople.age.set(19);  
mPeople.isMan.set(true);  
...

也不多说了。

Observable Collections 
既然普通的变量我们有了ObservableFields的分装,那集合呢?当然也有啦,来看着两个:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同,直接看代码:

<layout xmlns:android="http://schemas.android.com/apk/res/android">  
    <data class=".Custom">  
        <variable  
            name="map"  
            type="android.databinding.ObservableArrayMap<String,String>" />  
        <variable  
            name="list"  
            type="android.databinding.ObservableArrayList<String>" />  
    </data>  
    <LinearLayout  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:orientation="vertical">  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="@{map[`name`]}"/>  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="@{list[0]}"/>  
    </LinearLayout>  
</layout>

在布局中,使用方式和普通的集合一样,如果看不太懂,可以往上翻博客,看上面的集合是怎么使用的。 
在来看java文件,怎么设置数据,

ObservableArrayMap<String, String> map = new ObservableArrayMap<>();  
ObservableArrayList<String> list = new ObservableArrayList<>();  
map.put("name", "loader or qibin");  
list.add("loader!!!");  
binding.setMap(map);  
binding.setList(list);

太简单了,简直和ListMap使用方法一模一样!!!
十、inflate 
不知道大家注意没有,上面的代码我们都是在activity中通过DataBindingUtil.setContentView来加载的布局的,现在有个问题了,如果我们是在Fragment中使用呢?Fragment没有setContentView怎么办?不要着急,Data Binding也提供了inflate的支持! 
使用方法如下,大家肯定会觉得非常眼熟。

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);  
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

接下来,我们就尝试着在Fragment中使用一下Data Binding吧。 
首先还是那个学生类,Student

public class Student extends BaseObservable {  
    private String name;  
    private int age;  
  
    public Student() {  
    }  
  
    public Student(int age, String name) {  
        this.age = age;  
        this.name = name;  
    }  
  
    @Bindable  
    public int getAge() {  
        return age;  
    }  
  
    public void setAge(int age) {  
        this.age = age;  
        notifyPropertyChanged(org.loader.app5.BR.age);  
    }  
  
    @Bindable  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
        notifyPropertyChanged(org.loader.app5.BR.name);  
    }  
}

继续,activity的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".MainActivity">  
  
    <FrameLayout  
        android:id="@+id/container"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"/>  
  
</RelativeLayout>

activity的代码,

public class MainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        getSupportFragmentManager().beginTransaction()  
                .replace(R.id.container, new MyFragment()).commit();  
    }  
}

重点来了,我们这里data binding的操作都放在了fragment里,那么我们先来看看fragment的布局。

<layout xmlns:android="http://schemas.android.com/apk/res/android">  
    <data class=".Custom">  
        <import type="org.loader.app5.Student" />  
        <variable  
            name="stu"  
            type="Student" />  
        <variable  
            name="frag"  
            type="org.loader.app5.MyFragment" />  
    </data>  
  
    <LinearLayout  
        android:orientation="vertical"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content">  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:onClick="@{frag.click}"  
            android:text="@{stu.name}"/>  
  
        <TextView  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="@{String.valueOf(stu.age)}"/>  
    </LinearLayout>  
</layout>

两个TextView分别绑定了Student的name和age字段,而且给name添加了一个点击事件,点击后会调用Fragment的click方法。我们来迫不及待的看一下Fragment怎么写:

public class MyFragment extends Fragment {  
  
    private Student mStu;  
  
    @Nullable  
    @Override  
    public View onCreateView(LayoutInflater inflater,  
                             ViewGroup container, Bundle savedInstanceState) {  
        org.loader.app5.Custom binding = DataBindingUtil.inflate(inflater,  
                R.layout.frag_layout, container, false);  
        mStu = new Student(20, "loader");  
        binding.setStu(mStu);  
        binding.setFrag(this);  
        return binding.getRoot();  
    }  
  
    public void click(View view) {  
        mStu.setName("qibin");  
        mStu.setAge(18);  
    }  
}

onCreateView中, 不同于在Activity中,这里我们使用了DataBindingUtil.inflate方法,接受4个参数,第一个参数是一个 LayoutInflater对象,正好,我们这里可以使用onCreateView的第一个参数,第二个参数是我们的布局文件,第三个参数是一个 ViewGroup,第四个参数是一个boolean类型的,和在LayoutInflater.inflate一样,后两个参数决定了是否想container中添加我们加载进来的布局。 
下面的代码和我们之前写的并无差别,但是有一点,onCreateView方法需要返回一个View对象,我们从哪获取呢?ViewDataBinding有一个方法getRoot可以获取我们加载的布局,是不是很简单? 
来看一下效果:


本文转载自:http://blog.csdn.net/jdsjlzx/article/details/48133293

共有 人打赏支持
i
粉丝 1
博文 8
码字总数 4816
作品 0
石家庄
Android DataBinding 实战全解

2015年的Google IO大会上,Android 团队发布了一个数据绑定框架(Data Binding Library),官方原生支持 MVVM 模型。数据绑定的概念并不陌生,Web开发中已经很是普遍,因此DataBinding或多或...

sunrongxin.py
2017/07/17
0
0
google data binding框架,与MVVM

> DataBinding 框架 This is a demo for android data binding- https://github.com/mmlovesyy/LoginDemo4DataBinding DataBindingDemo- https://github.com/dragonjiang/DataBindingDemo 20......

desaco
09/20
0
0
Android之MVVM架构指南(二):DataBinding

DataBinding 出现的目的旨在取代方法,但是它的功能不仅如此。 配置 在中开启功能 在中启用新的编译器 基本操作 实现一个databinding基本上需要完成三个步骤的工作 1. 创建数据源 即普通的J...

吴七禁
今天
0
0
android -------- Data Binding的使用(一)

Google推出自己官方的数据绑定框架Data Binding Library 已经很久了,很多企业也在使用 面试的时候也有问到,所以也去学习了一番,特来分享一下,希望对各位有所帮助 描述: Data Binding 是...

切切歆语
07/18
0
0
使用Kotlin构建更适合Android的MVVM应用程序

简书地址:www.jianshu.com/p/77e42aebd… 概述 说到MVVM,大家都会想起前端的MVVM框架,相较于前端MVVM的火热,它在移动开发领域就不那么热门了。Google在2015年才推出DataBinding框架,起步...

ditclear
2017/11/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

关于Jackson默认丢失Bigdecimal精度问题分析

问题描述 最近在使用一个内部的RPC框架时,发现如果使用Object类型,实际类型为BigDecimal的时候,作为传输对象的时候,会出现丢失精度的问题;比如在序列化前为金额1.00,反序列化之后为1.0...

ksfzhaohui
19分钟前
0
0
vue less安装

$ npm install less less-loader --save 安装成功后修改文件:build>webpack.base.conf.js 在model.rules添加对象: { test: /\.less$/, loader: "style-loader!css-loader!less-loade......

shawnDream
24分钟前
0
0
kolla-ansible部署容器ceph

kolla是从openstack孵化出的一个项目,kolla项目可以制作镜像包括openstack、ceph等容器镜像, ansible是自动化部署工具,执行playbook中的任务。 kolla-ansible是容器部署工具,部署opensta...

zrz11
29分钟前
0
0
【三 异步HTTP编程】 1. 处理异步results

异步results 事实上整个Play框架都是异步的。Play非阻塞地处理每个request请求。 默认的配置适配的正是异步的controller。因此开发者应该尽力避免在在controller中阻塞,如在controller方法中...

Landas
31分钟前
0
0
Android Studio 3.1.4 buildApk遇到问题 Connection reset

打开设置,找到Android Studio选项卡,把下图选项打上勾就ok

lanyu96
32分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部