- 浏览: 2215725 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
Android新推出了一个官方的数据绑定框架Data Binding Library,既然是官方推出的新玩意,我们就有必要了解一下Android新带来的数据绑定框架,等到该框架推出正式版的时候,我们就可以快速地运用到项目中去。数据绑定框架给我们带来了很大的方便性,以前我们可能需要在Activity里写很多的findViewById,烦人的代码也增加了我们代码的耦合性,现在我们马上就可以抛弃那些findViewById。说到这里,有人可能会问:我使用的一些注解框架也可以不用findViewById啊,是的,但是注解的缺点是拖累代码的效率,Data Binding则不会,Android官方文档说还会提高解析XML的速度,最主要的是Data Binding并不是单单减少我们的findViewById,更多的好处我们接下来一起探寻。
1.环境
使用最新的Android Studio 1.5.1正式版,并更新你的Suport Repository到最新的版本,确保Android Studio的Gradle插件不低于1.5.0
然后修改对应模块(Module)的build.gradle,添加如下脚本代码:
最后,点击Sync同步一下Gradle即可完成环境配置
2.Data Binding示例
首先,我们需要新建一个Java Bean,一个简单的学生类。
其次,编写布局文件data_binding.xml:
最后,实现MainActivity,为变量赋值
由上面可以看出,MainActivity的代码非常简单,就添加了两行代码,需要注意的是我们并没有findViewById然后再去setText。
运行结果如下图所示:
3.Data Binding详解
上面的示例仅仅是带领我们进入了Data Binding的世界,接下来我们解释一下Data Binding的开发步骤。先看看上面的布局文件。
根节点使用的是layout,在layout中分成两部分,第一部分是data节点,第二部分才是我们布局的根节点,在data节点下我们定义了一个variable,它是一个变量,变量名称是stu,类型是com.example.iaiai.databinding.Student,这类似我们在java文件中的定义:
不过这里要写Student完整的包名,如果这里我们需要多个Student呢?我们可以像写java文件那样导入类包
这样就类似于java中的
既然变量定义好了,那该怎么使用呢?我们仍然看上面的xml文件
由上面可以看出,两个TextView的android:text,它的值是以@开始,以{}包裹的形式出现,而值呢?是stu.name,stu就是上面定义的variable,name就是Student类中的成员变量,其实这里就会去调用stu.getName()方法。
最后,我们看看如何给变量赋值呢?如下代码:
大部分情况,我们会在Activity中去使用它,以前我们都是在OnCreate方法中通过setContextView去设置布局。但现在不一样了,现在我们是通过DataBindingUtil类的一个静态方法setContentView设置布局,同时该方法会返回一个对象,这个对象时一个自动生成的类的对象,如DataBindingBinding?那么它的命名规则是什么呢?将我们布局文件的首字母大写,并且去掉下划线,将下划线后面的字母大写,加上后缀Binding组成。最后,我们通过这个对象来给变量赋值。
通过以上分析,我们了解Data Binding的具体开发步骤,下面让我们定义不同的几个变量看看
由上面代码可以看出,String类型的变量没有导入包,这是因为Data Binding和Java一样,java.lang包里的类,我们是可以不用导入包的,再往下一个boolean和int类型的变量,都是java基本类型,也不用导入包。
再来看看几个TextView,第二个TextView,我们直接使用@{str}来为android:text设置文本内容;接下来注意第三个TextView,我们使用android:text="@{String.valueOf(num)}"来设置一个int类型的变量,因为在给android:text设置int类型的值一定要转化为String类型,不然系统会认为是资源文件id。此外,我们还学习到了一点,在Xml中,我们不仅可以使用变量,而且还可以调用方法
4. 变量定义的高级部分
在上面,我们学会了如何在xml中定义变量,但是我们并没有定义像List、Map等这样的集合变量。那么到底能不能定义呢?答案是肯定的,而且定义的方式和我们上面的基本一致,区别就在于我们还需要为它定义key的变量,例如:
然后在java代码中为变量赋值
5.表达式
xml中还支持表达式
如上所示,android:text后是一个三元表达式,如果error是true,则text就是error,否则是OK。
除此外还支持null合并操作,??--左边的对象如果它不是null,选择左边的对象;或者如果它是null,选择右边的对象
还支持以下表达式:
示例:
但是它不支持一下表达式:
6. 其他知识点
6.1 设置别名
假如我们import了两个相同名称的类咋办?我们可以借助于别名来解决,别名借助alias字段来标识,例如:
6.2 自定义Binding类名称
默认情况下,Binding类的命名是基于所述layout文件的名称,用大写开头,除去下划线()以及()后的第一个字母大写,然后添加“Binding”后缀。这个类将被放置在一个模块封装包里的databinding封装包下。例如,所述layout文件contact_item.xml将生成ContactItemBinding。如果模块包是com.example.my.app,那么它将被放置在com.example.my.app.databinding。
Binding类可通过调整data元素中的class属性来重命名或放置在不同的包中。例如:
在模块封装包的databinding包中会生成名为ContactItem的Binding类。如果要想让该类生成在不同的包中,你需要添加前缀.,如下:
在这个情况下,ContactItem类直接在模块包中生成。或者你可以提供整个包名:
6.3 字符串
当使用单引号包含属性值时,在表达式中使用双引号很容易:
android:text='@{map["firstName"]}'
使用双引号来包含属性值也是可以的。字符串前后需要使用"":
android:text="@{map[`firstName`]}"
6.4 Resources
使用正常的表达式来访问resources也是可行的:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
6.5 include
通过使用application namespace以及在属性中的Variable名字从容器layout中传递Variables到一个被包含的layout:
注意:在name.xml以及contact.xml两个layout文件中必需要有user variable
7.事件绑定
大家都知道,在xml中我们可以给button设置一个onClick来达到事件的绑定,现在DataBinding也提供了事件绑定,而且不仅仅是button。首先定义一个对象处理点击事件,如下:
其次看布局:
最后,实现事件绑定
8.Data对象
我们学会了通过binding为我们的变量设置数据,但是不知道你有没有发现一个问题,当我们数据改变的时候会怎样?数据是跟随着改变呢?还是原来的数据呢?这里告诉你答案:很不幸,显示的还是原来的数据?那有没有办法让数据源发生变化后显示的数据也随之发生变化?先来想想ListView是怎么做的, ListView的数据是通过Adapter提供的,当数据发生改变时,我们通过notifyDatasetChanged通过UI去改变数据,这里面的原理其实就是内容观察者,庆幸的是DataBinding也支持内容观察者,而且使用起来也相当方便!
8.1 Observable
我们可以通过Observable的方式去通知UI数据已经改变了,当然了,官方为我们提供了更加简便的方式BaseObservable,我们的实体类只需要继承该类,稍做几个操作,就能轻松实现数据变化的通知。如何使用呢? 首先我们的实体类要继承BaseObservale类,第二步在Getter上使用注解@Bindable,第三步,在Setter里调用方法notifyPropertyChanged,第四步,完成。就是这么简单,下面我们来实际操作一下。
首先定义一个实体类,并继承BaseObservable
观察getName方法,我们使用了@Bindable注解,观察setName,我们调用了notifyPropertyChanged方法,这个方法还需要一个参数,这里参数类似于R.java,保存了我们所有变量的引用地址,这里我们使用了name。
其次,看看布局文件
最后,java实现
8.2 ObservableFields
上面使用BaseObservable已经非常容易了,但是google工程师还不满足,继续给我们封装了一系列的ObservableFields,这里有ObservableField,ObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable
ObservableFields的使用方法就更加简单了,例如下面代码:
很简单,只有三个ObservableField变量,并且没有getter和setter,因为我们不需要getter和setter。
在xml中怎么使用呢?
也很简单,直接使用变量,那怎么赋值和取值呢?这些ObservableField都会有一对get和set方法,所以使用起来也很方便了:
8.3 Observable Collections
既然普通的变量我们有了ObservableFields的分装,那集合呢?当然也有啦,来看着两个:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同,直接看代码:
在来看java文件,怎么设置数据
9.Inflate
上面的代码我们都是在activity中通过DataBindingUtil.setContentView来加载的布局的,现在有个问题了,如果我们是在Fragment中使用呢?Fragment没有setContentView怎么办?不要着急,Data Binding也提供了inflate的支持!
使用方法如下,大家肯定会觉得非常眼熟。
接下来,我们就尝试着在Fragment中使用一下Data Binding吧。
首先还是那个学生类,Student
其次,activity的布局
Activity的实现
重点来了,我们这里data binding的操作都放在了fragment里,那么我们先来看看fragment的布局。
两个TextView分别绑定了Student的name和age字段,而且给name添加了一个点击事件,点击后会调用Fragment的click方法。我们来迫不及待的看一下Fragment怎么写:
在onCreateView中,不同于在Activity中,这里我们使用了DataBindingUtil.inflate方法,接受4个参数,第一个参数是一个LayoutInflater对象,正好,我们这里可以使用onCreateView的第一个参数,第二个参数是我们的布局文件,第三个参数是一个ViewGroup,第四个参数是一个boolean类型的,和在LayoutInflater.inflate一样,后两个参数决定了是否想container中添加我们加载进来的布局。
下面的代码和我们之前写的并无差别,但是有一点,onCreateView方法需要返回一个View对象,我们从哪获取呢?ViewDataBinding有一个方法getRoot可以获取我们加载的布局,是不是很简单?
来看一下效果:
10.Data Binding VS RecyclerView
有了上面的思路,大家是不是也会在ListView和RecyclerView中使用了?我们仅以一个RecyclerView来学习一下。
首先来看看item的布局,
可以看到,还是用了那个Student实体,这样得代码,相信你也已经看烦了吧。
那我们来看看activity的。
这里给RecyclerView设置了一个Adapter,相信最主要的代码就在这个Adapter里。
果然,这个adapter的写法和我们之前的写法不太一样,首先看看ViewHolder,在这个holder里,我们保存了一个ViewDataBinding对象,并给它提供了Getter和Setter方法, 这个ViewDataBinding是干嘛的?我们稍后去讲。继续看看onCreateViewHolder,在这里面,我们首先调用DataBindingUtil.inflate方法返回了一个ViewDataBinding的对象,这个ViewDataBinding是个啥?我们以前没见过啊,这里告诉大家我们之前返回的那些都是ViewDataBinding的子类!继续看代码,我们new了一个holder,参数是肯定是我们的item布局了,继续看,接着我们又把binding设置给了holder,最后返回holder。这时候,我们的holder里就保存了刚刚返回的ViewDataBinding对象,干嘛用呢?继续看onBindViewHolder就知道了。
只有两行代码,但是都是我们没有见过的,首先第一行,我们以前都是使用类似binding.setStu这样方法去设置变量,那这个setVariable呢? 为什么没有setStu,这里要记住,ViewDataBinding是我们之前用的那些binding的父类,只有自动生成的那些子类才会有setXXX方法,那现在我们需要在ViewDataBinding中设置变量咋办?这个类为我们提供了setVariable去设置变量,第一个参数是我们的变量名的引用,第二个是我们要设置的值。
第二行代码,executePendingBindings的作用是干嘛的?
官方的回答是:
当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。
所以这里的作用就是去让数据的改变立即执行。
ok,现在看起来,我们的代码更加简洁了,而且不需要保存控件的实例,是不是很爽? 来看看效果:
11.View with ID
在使用Data Binding的过程中,我们发现并没有保存View的实例,但是现在我们有需求需要这个View的实例咋办?难道走老路findViewById?当然不是啦,当我们需要某个view的实例时,我们只要给该view一个id,然后Data Binding框架就会给我们自动生成该view的实例,放哪了?当然是ViewDataBinding里面。
上代码:
xml中代码没有什么好说的,都是之前的代码。需要注意的是,
我们给TextView设定了一个id-textView。
activity代码如下:
通过ViewDataBinding类的实例直接去获取的。只要我们给了view一个id,那么框架就会在ViewDataBinding中自动帮我们保存这个view的实例,变量名就是我们设置的id。
12.自定义setter(BindingAdapter)
想想这样的一种情景,一个ImageView需要通过网络去加载图片,那我们怎么办?看似好像使用DataBinding不行,恩,我们上面所学到东西确实不能够解决这个问题,但是DataBinding框架给我们提供了很好的扩展,允许我们自定义setter,那该怎么做呢?这里就要引出另一个知识点——BindingAdapter,这是一个注解,参数是一个数组,数组中存放的是我们自定义的’属性’。接下来就以一个例子学习一下BindingAdapter的使用。
这里我们增加了一个命名空间app,并且注意ImageView的app:image属性,这里和我们自定义view时自定义的属性一样,但是这里并不需要我们去重写ImageView,这条属性的值是我们上面定义的String类型的imageUrl,从名称中看到这里我们可能会塞给他一个url。
activity代码如下:
果然在这里我们set了一个url,那图片怎么加载呢?这里就要使用到我们刚才说的BindingAdapter注解了。
我们定义了一个Utils类,这个类你可以随便起名,该类中只有一个静态的方法imageLoader,该方法有两个参数,一个是需要设置数据的view,
一个是我们需要的url。值得注意的是那个BindingAdapter注解,看看他的参数,是一个数组,内容只有一个bind:image,仅仅几行代码,我们不需要 手工调用Utils.imageLoader,也不需要知道imageLoader方法定义到哪了,一个网络图片加载就搞定了,是不是很神奇,这里面起关键作用的就是BindingAdapter 注解了,来看看它的参数怎么定义的吧,难道是乱写?当然不是,这里要遵循一定的规则,
这里就是image了,不信来看。
13.Converters
Converter是什么呢?举个例子吧:假如你的控件需要一个格式化好的时间,但是你只有一个Date类型额变量咋办?肯定有人会说这个简单,转化完成后在设置,恩,这也是一种办法,但是DataBinding还给我们提供了另外一种方式,虽然原理一样,但是这种方式使用的场景更多,那就是——Converter。和上面的BindingAdapter使用方法一样,这也是一个注解。下面还是以一段代码的形式进行学习。
看TextView的text属性,我们需要一个String类型的值,但是这里确给了一个Date类型的,这就需要我们去定义Converter去转换它,
activity代码如下:
去给这个Date类型的变量设置值。怎么去定义Converter呢? 看代码:
和上面一样,我们不需要关心这个convertDate在哪个类中,重要的是他的@BindingConversion注解,这个方法接受一个Date类型的变量,正好我们的android:text设置的就是一个Date类型的值,在方法内部我们将这个Date类型的变量转换成String类型的日期并且返回。这样UI上就显示出我们转化好的字符串。
看看效果:
1.环境
使用最新的Android Studio 1.5.1正式版,并更新你的Suport Repository到最新的版本,确保Android Studio的Gradle插件不低于1.5.0
classpath 'com.android.tools.build:gradle:1.5.0'
然后修改对应模块(Module)的build.gradle,添加如下脚本代码:
android { //添加DataBinding Library dataBinding { enabled true } }
最后,点击Sync同步一下Gradle即可完成环境配置
2.Data Binding示例
首先,我们需要新建一个Java Bean,一个简单的学生类。
package com.example.iaiai.databinding; /** * Created by iaiai on 2016/2/16. */ public class Student { private String name; private String addr; public Student() { } public Student(String name,String addr) { this.addr = addr; this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }
其次,编写布局文件data_binding.xml:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <variable name="stu" type="com.example.iaiai.databinding.Student" /> </data> <LinearLayout android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{stu.name}"/> //也可以是android:text="@{stu.getName()}" <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{stu.addr}"/> //也可以是android:text="@{stu.getAddr()}" </LinearLayout> </layout>
最后,实现MainActivity,为变量赋值
import com.example.iaiai.databinding.databinding.DataBindingBinding; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DataBindingBinding binding = DataBindingUtil.setContentView(this, R.layout.data_binding); binding.setStu(new Student("lee", "Shenzhen")); }
由上面可以看出,MainActivity的代码非常简单,就添加了两行代码,需要注意的是我们并没有findViewById然后再去setText。
运行结果如下图所示:
3.Data Binding详解
上面的示例仅仅是带领我们进入了Data Binding的世界,接下来我们解释一下Data Binding的开发步骤。先看看上面的布局文件。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <variable name="stu" type="com.example.iaiai.databinding.Student" /> </data> .....
根节点使用的是layout,在layout中分成两部分,第一部分是data节点,第二部分才是我们布局的根节点,在data节点下我们定义了一个variable,它是一个变量,变量名称是stu,类型是com.example.iaiai.databinding.Student,这类似我们在java文件中的定义:
com.example.iaiai.databinding.Student stu;
不过这里要写Student完整的包名,如果这里我们需要多个Student呢?我们可以像写java文件那样导入类包
<layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <!--导入类包--> <import type="com.example.iaiai.databinding.Student"/> <variable name="stu" type="Student" /> </data> ..... </layout>
这样就类似于java中的
import com.example.iaiai.databinding.Student; Student stu1,stu2,...
既然变量定义好了,那该怎么使用呢?我们仍然看上面的xml文件
<layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> .... <LinearLayout android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{stu.name}"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{stu.addr}"/> </LinearLayout> </layout>
由上面可以看出,两个TextView的android:text,它的值是以@开始,以{}包裹的形式出现,而值呢?是stu.name,stu就是上面定义的variable,name就是Student类中的成员变量,其实这里就会去调用stu.getName()方法。
最后,我们看看如何给变量赋值呢?如下代码:
import com.example.iaiai.databinding.databinding.DataBindingBinding; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DataBindingBinding binding = DataBindingUtil.setContentView(this, R.layout.data_binding); binding.setStu(new Student("lee", "Shenzhen")); //赋值 }
大部分情况,我们会在Activity中去使用它,以前我们都是在OnCreate方法中通过setContextView去设置布局。但现在不一样了,现在我们是通过DataBindingUtil类的一个静态方法setContentView设置布局,同时该方法会返回一个对象,这个对象时一个自动生成的类的对象,如DataBindingBinding?那么它的命名规则是什么呢?将我们布局文件的首字母大写,并且去掉下划线,将下划线后面的字母大写,加上后缀Binding组成。最后,我们通过这个对象来给变量赋值。
通过以上分析,我们了解Data Binding的具体开发步骤,下面让我们定义不同的几个变量看看
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <import type="com.example.iaiai.databinding.Student" /> <variable name="stu" type="Student" /> <variable name="str" type="String"/> <variable name="error" type="boolean"/> <variable name="num" type="int" /> </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:text="@{stu.name}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{str}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(num)}"/> </LinearLayout> </layout>
由上面代码可以看出,String类型的变量没有导入包,这是因为Data Binding和Java一样,java.lang包里的类,我们是可以不用导入包的,再往下一个boolean和int类型的变量,都是java基本类型,也不用导入包。
再来看看几个TextView,第二个TextView,我们直接使用@{str}来为android:text设置文本内容;接下来注意第三个TextView,我们使用android:text="@{String.valueOf(num)}"来设置一个int类型的变量,因为在给android:text设置int类型的值一定要转化为String类型,不然系统会认为是资源文件id。此外,我们还学习到了一点,在Xml中,我们不仅可以使用变量,而且还可以调用方法
4. 变量定义的高级部分
在上面,我们学会了如何在xml中定义变量,但是我们并没有定义像List、Map等这样的集合变量。那么到底能不能定义呢?答案是肯定的,而且定义的方式和我们上面的基本一致,区别就在于我们还需要为它定义key的变量,例如:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <!--导入类包--> <import type="com.example.iaiai.databinding.Student" /> <import type="android.graphics.Bitmap" /> <import type="java.util.ArrayList" /> <import type="java.util.HashMap" /> <variable name="stu" type="Student" /> <variable name="str" type="String" /> <variable name="error" type="boolean" /> <variable name="num" type="int" /> <variable name="list" type="ArrayList<String>" /> <variable name="map" type="HashMap<String, String>" /> <variable name="array" type="String[]" /> <variable name="listKey" type="int" /> <variable name="mapKey" type="String" /> <variable name="arrayKey" type="int" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{stu.name}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{str}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(num)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{list[listKey]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{map[mapKey]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{array[arrayKey]}" /> </LinearLayout> </layout>
然后在java代码中为变量赋值
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DataBindingBinding binding = DataBindingUtil.setContentView(this, R.layout.data_binding); binding.setStu(new Student("lee", "Shenzhen")); binding.setStr("just do it"); binding.setNum(10); ArrayList<String> list = new ArrayList<String>(); list.add("list1"); list.add("list2"); binding.setList(list); binding.setListKey(0); HashMap<String,String> map = new HashMap<String,String>(); map.put("name","liu"); map.put("sex","male"); binding.setMap(map); binding.setMapKey("sex"); String[] array = new String[2]; array[0] = "array0"; array[1] = "array1"; binding.setArray(array); binding.setArrayKey(1); }
5.表达式
xml中还支持表达式
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{error ? "error" : "ok"}'/>
如上所示,android:text后是一个三元表达式,如果error是true,则text就是error,否则是OK。
除此外还支持null合并操作,??--左边的对象如果它不是null,选择左边的对象;或者如果它是null,选择右边的对象
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{str ?? "not null"}' />
还支持以下表达式:
- 数学 + - / * %
- 字符串连接 +
- 逻辑 && ||
- 二进制 & | ^
- 一元运算 + - ! ~
- 移位 >> >>> <<
- 比较 == > < >= <=
- instanceof
- 分组 ()
- null
- Cast
- 方法调用
- 数据访问 []
- 三元运算 ?:
示例:
android:text="@{String.valueOf(index + 1)}" android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}" android:transitionName='@{"image_" + id}'
但是它不支持一下表达式:
- this
- super
- new
- 显式泛型调用
6. 其他知识点
6.1 设置别名
假如我们import了两个相同名称的类咋办?我们可以借助于别名来解决,别名借助alias字段来标识,例如:
<data> <import type="xxx.Name" alias="MyName"> <import type="xxx.xx.Name"> </data> <TextView xxx:@{MyName.getName()}> <TextView xxx:@{Name.getName()}>
6.2 自定义Binding类名称
默认情况下,Binding类的命名是基于所述layout文件的名称,用大写开头,除去下划线()以及()后的第一个字母大写,然后添加“Binding”后缀。这个类将被放置在一个模块封装包里的databinding封装包下。例如,所述layout文件contact_item.xml将生成ContactItemBinding。如果模块包是com.example.my.app,那么它将被放置在com.example.my.app.databinding。
Binding类可通过调整data元素中的class属性来重命名或放置在不同的包中。例如:
<data class="ContactItem"> ... </data>
在模块封装包的databinding包中会生成名为ContactItem的Binding类。如果要想让该类生成在不同的包中,你需要添加前缀.,如下:
<data class=".ContactItem"> ... </data>
在这个情况下,ContactItem类直接在模块包中生成。或者你可以提供整个包名:
<data class="com.example.ContactItem"> ... </data>
6.3 字符串
当使用单引号包含属性值时,在表达式中使用双引号很容易:
android:text='@{map["firstName"]}'
使用双引号来包含属性值也是可以的。字符串前后需要使用"":
android:text="@{map[`firstName`]}"
6.4 Resources
使用正常的表达式来访问resources也是可行的:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
6.5 include
通过使用application namespace以及在属性中的Variable名字从容器layout中传递Variables到一个被包含的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>
注意:在name.xml以及contact.xml两个layout文件中必需要有user variable
7.事件绑定
大家都知道,在xml中我们可以给button设置一个onClick来达到事件的绑定,现在DataBinding也提供了事件绑定,而且不仅仅是button。首先定义一个对象处理点击事件,如下:
/** * Created by iaiai on 2016/2/16. */ public class EventHandler { public void handleClick(View view) { Toast.makeText(view.getContext(),"click",Toast.LENGTH_SHORT).show(); } }
其次看布局:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <import type="com.example.iaiai.databinding.EventHandler" /> <variable name="handler" type="EventHandler" /> </data> <LinearLayout android:orientation="vertical"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Click" android:onClick="@{handler.handleClick}"/> </LinearLayout> </layout>
最后,实现事件绑定
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ClickBindingBinding binding = DataBindingUtil.setContentView(this, R.layout.click_binding); binding.setHandler(new EventHandler()); }
8.Data对象
我们学会了通过binding为我们的变量设置数据,但是不知道你有没有发现一个问题,当我们数据改变的时候会怎样?数据是跟随着改变呢?还是原来的数据呢?这里告诉你答案:很不幸,显示的还是原来的数据?那有没有办法让数据源发生变化后显示的数据也随之发生变化?先来想想ListView是怎么做的, ListView的数据是通过Adapter提供的,当数据发生改变时,我们通过notifyDatasetChanged通过UI去改变数据,这里面的原理其实就是内容观察者,庆幸的是DataBinding也支持内容观察者,而且使用起来也相当方便!
8.1 Observable
我们可以通过Observable的方式去通知UI数据已经改变了,当然了,官方为我们提供了更加简便的方式BaseObservable,我们的实体类只需要继承该类,稍做几个操作,就能轻松实现数据变化的通知。如何使用呢? 首先我们的实体类要继承BaseObservale类,第二步在Getter上使用注解@Bindable,第三步,在Setter里调用方法notifyPropertyChanged,第四步,完成。就是这么简单,下面我们来实际操作一下。
首先定义一个实体类,并继承BaseObservable
/** * Created by iaiai on 2016/2/16. */ public class Student extends BaseObservable{ private String name; private String addr; public Student() { } public Student(String name,String addr) { this.addr = addr; this.name = name; } @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(com.example.iaiai.databinding.BR.name); } @Bindable public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; notifyPropertyChanged(com.example.iaiai.databinding.BR.addr); } }
观察getName方法,我们使用了@Bindable注解,观察setName,我们调用了notifyPropertyChanged方法,这个方法还需要一个参数,这里参数类似于R.java,保存了我们所有变量的引用地址,这里我们使用了name。
其次,看看布局文件
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <data> <import type="com.example.iaiai.databinding.Student" /> <variable name="stu" type="Student"/> <variable name="click" type="com.example.iaiai.databinding.MainActivity" /> </data> <LinearLayout android:orientation="vertical"> <TextView android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{stu.name+stu.addr}" android:onClick="@{click.click}"/> </LinearLayout> </layout>
最后,java实现
public class MainActivity extends AppCompatActivity { private Student mStu; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ClickBindingBinding binding = DataBindingUtil.setContentView(this, R.layout.click_binding); mStu = new Student("lau","Shenzhen"); binding.setStu(mStu); //设置初始显示数据 binding.setClick(this); //设置点击事件 } public void click(View view) { //点击时数据发生改变 mStu.setName("lee"); mStu.setAddr("Beijing"); } }
8.2 ObservableFields
上面使用BaseObservable已经非常容易了,但是google工程师还不满足,继续给我们封装了一系列的ObservableFields,这里有ObservableField,ObservableBoolean,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都会有一对get和set方法,所以使用起来也很方便了:
mPeople = new People(); binding.setPeople(mPeople); mPeople.name.set("people"); mPeople.age.set(19); mPeople.isMan.set(true);
8.3 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);
9.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可以获取我们加载的布局,是不是很简单?
来看一下效果:

10.Data Binding VS RecyclerView
有了上面的思路,大家是不是也会在ListView和RecyclerView中使用了?我们仅以一个RecyclerView来学习一下。
首先来看看item的布局,
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="stu" type="org.loader.app6.Student" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{stu.name}" android:layout_alignParentLeft="true"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(stu.age)}" android:layout_alignParentRight="true"/> </RelativeLayout> </layout>
可以看到,还是用了那个Student实体,这样得代码,相信你也已经看烦了吧。
那我们来看看activity的。
private RecyclerView mRecyclerView; private ArrayList<Student> mData = new ArrayList<Student>() { { for (int i=0;i<10;i++) add(new Student("loader" + i, 18 + i)); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.recycler); mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); mRecyclerView.setAdapter(new MyAdapter(mData)); }
这里给RecyclerView设置了一个Adapter,相信最主要的代码就在这个Adapter里。
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private ArrayList<Student> mData = new ArrayList<>(); private MyAdapter(ArrayList<Student> data) { mData.addAll(data); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater .from(viewGroup.getContext()), R.layout.item, viewGroup, false); ViewHolder holder = new ViewHolder(binding.getRoot()); holder.setBinding(binding); return holder; } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i)); viewHolder.getBinding().executePendingBindings(); } @Override public int getItemCount() { return mData.size(); } class ViewHolder extends RecyclerView.ViewHolder { private ViewDataBinding binding; public ViewHolder(View itemView) { super(itemView); } public void setBinding(ViewDataBinding binding) { this.binding = binding; } public ViewDataBinding getBinding() { return this.binding; } }
果然,这个adapter的写法和我们之前的写法不太一样,首先看看ViewHolder,在这个holder里,我们保存了一个ViewDataBinding对象,并给它提供了Getter和Setter方法, 这个ViewDataBinding是干嘛的?我们稍后去讲。继续看看onCreateViewHolder,在这里面,我们首先调用DataBindingUtil.inflate方法返回了一个ViewDataBinding的对象,这个ViewDataBinding是个啥?我们以前没见过啊,这里告诉大家我们之前返回的那些都是ViewDataBinding的子类!继续看代码,我们new了一个holder,参数是肯定是我们的item布局了,继续看,接着我们又把binding设置给了holder,最后返回holder。这时候,我们的holder里就保存了刚刚返回的ViewDataBinding对象,干嘛用呢?继续看onBindViewHolder就知道了。
@Override public void onBindViewHolder(ViewHolder viewHolder, int i) { viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i)); viewHolder.getBinding().executePendingBindings(); }
只有两行代码,但是都是我们没有见过的,首先第一行,我们以前都是使用类似binding.setStu这样方法去设置变量,那这个setVariable呢? 为什么没有setStu,这里要记住,ViewDataBinding是我们之前用的那些binding的父类,只有自动生成的那些子类才会有setXXX方法,那现在我们需要在ViewDataBinding中设置变量咋办?这个类为我们提供了setVariable去设置变量,第一个参数是我们的变量名的引用,第二个是我们要设置的值。
第二行代码,executePendingBindings的作用是干嘛的?
官方的回答是:
当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。
所以这里的作用就是去让数据的改变立即执行。
ok,现在看起来,我们的代码更加简洁了,而且不需要保存控件的实例,是不是很爽? 来看看效果:

11.View with ID
在使用Data Binding的过程中,我们发现并没有保存View的实例,但是现在我们有需求需要这个View的实例咋办?难道走老路findViewById?当然不是啦,当我们需要某个view的实例时,我们只要给该view一个id,然后Data Binding框架就会给我们自动生成该view的实例,放哪了?当然是ViewDataBinding里面。
上代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class=".Custom"> <variable name="str" type="android.databinding.ObservableField<String>" /> <variable name="handler" type="org.loader.app7.MainActivity" /> </data> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{str.get}" android:onClick="@{handler.click}"/> </layout>
xml中代码没有什么好说的,都是之前的代码。需要注意的是,
我们给TextView设定了一个id-textView。
activity代码如下:
public class MainActivity extends AppCompatActivity { private org.loader.app7.Custom mBinding; private ObservableField<String> mString; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); mString = new ObservableField<String>(); mString.set("loader"); mBinding.setStr(mString); mBinding.setHandler(this); } public void click(View view) { mString.set("qibin"); mBinding.textView.setTextColor(Color.GREEN); //找到控件 } }
通过ViewDataBinding类的实例直接去获取的。只要我们给了view一个id,那么框架就会在ViewDataBinding中自动帮我们保存这个view的实例,变量名就是我们设置的id。
12.自定义setter(BindingAdapter)
想想这样的一种情景,一个ImageView需要通过网络去加载图片,那我们怎么办?看似好像使用DataBinding不行,恩,我们上面所学到东西确实不能够解决这个问题,但是DataBinding框架给我们提供了很好的扩展,允许我们自定义setter,那该怎么做呢?这里就要引出另一个知识点——BindingAdapter,这是一个注解,参数是一个数组,数组中存放的是我们自定义的’属性’。接下来就以一个例子学习一下BindingAdapter的使用。
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data class=".Custom"> <variable name="imageUrl" type="String" /> </data> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" app:image="@{imageUrl}"/> </layout>
这里我们增加了一个命名空间app,并且注意ImageView的app:image属性,这里和我们自定义view时自定义的属性一样,但是这里并不需要我们去重写ImageView,这条属性的值是我们上面定义的String类型的imageUrl,从名称中看到这里我们可能会塞给他一个url。
activity代码如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); org.loader.app8.Custom binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setImageUrl("http://images.csdn.net/20150810/Blog-Image%E5%89%AF%E6%9C%AC.jpg"); } }
果然在这里我们set了一个url,那图片怎么加载呢?这里就要使用到我们刚才说的BindingAdapter注解了。
public class Utils { @BindingAdapter({"bind:image"}) public static void imageLoader(ImageView imageView, String url) { ImageLoaderUtils.getInstance().displayImage(url, imageView); } }
我们定义了一个Utils类,这个类你可以随便起名,该类中只有一个静态的方法imageLoader,该方法有两个参数,一个是需要设置数据的view,
一个是我们需要的url。值得注意的是那个BindingAdapter注解,看看他的参数,是一个数组,内容只有一个bind:image,仅仅几行代码,我们不需要 手工调用Utils.imageLoader,也不需要知道imageLoader方法定义到哪了,一个网络图片加载就搞定了,是不是很神奇,这里面起关键作用的就是BindingAdapter 注解了,来看看它的参数怎么定义的吧,难道是乱写?当然不是,这里要遵循一定的规则,
引用
以bind:开头,接着书写你在控件中使用的自定义属性名称。
这里就是image了,不信来看。
<ImageView android:layout_width="match_parent" android:layout_height="wrap_content" app:image="@{imageUrl}"/>
13.Converters
Converter是什么呢?举个例子吧:假如你的控件需要一个格式化好的时间,但是你只有一个Date类型额变量咋办?肯定有人会说这个简单,转化完成后在设置,恩,这也是一种办法,但是DataBinding还给我们提供了另外一种方式,虽然原理一样,但是这种方式使用的场景更多,那就是——Converter。和上面的BindingAdapter使用方法一样,这也是一个注解。下面还是以一段代码的形式进行学习。
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class=".Custom"> <variable name="time" type="java.util.Date" /> </data> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{time}"/> </layout>
看TextView的text属性,我们需要一个String类型的值,但是这里确给了一个Date类型的,这就需要我们去定义Converter去转换它,
activity代码如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); org.loader.app9.Custom binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setTime(new Date()); } }
去给这个Date类型的变量设置值。怎么去定义Converter呢? 看代码:
public class Utils { @BindingConversion public static String convertDate(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.format(date); } }
和上面一样,我们不需要关心这个convertDate在哪个类中,重要的是他的@BindingConversion注解,这个方法接受一个Date类型的变量,正好我们的android:text设置的就是一个Date类型的值,在方法内部我们将这个Date类型的变量转换成String类型的日期并且返回。这样UI上就显示出我们转化好的字符串。
看看效果:

发表评论
-
带你深入理解 FLUTTER 中的字体“冷”知识
2020-08-10 23:40 656本篇将带你深入理解 Flutter 开发过程中关于字体和文 ... -
Flutter -自定义日历组件
2020-03-01 17:56 1132颜色文件和屏幕适配的文件 可以自己给定 import ... -
Dart高级(一)——泛型与Json To Bean
2020-02-23 19:13 1024从 Flutter 发布到现在, 越来越多人开始尝试使用 Da ... -
flutter loading、Progress进度条
2020-02-21 17:03 1201Flutter Progress 1 条形无固定值进度条 ... -
Flutter使用Https加载图片
2020-02-21 01:39 1045Flutter使用Https加载图片 使用http加载图片出 ... -
flutter shared_preferences 异步变同步
2020-02-21 00:55 863前言 引用 在开发原生iOS或Native应用时,一般有判断上 ... -
Flutter TextField边框颜色
2020-02-19 21:31 956监听要销毁 myController.dispose(); T ... -
flutter Future的正确用法
2020-02-18 21:55 816在flutter中经常会用到异步任务,dart中异步任务异步处 ... -
记一次Flutter简单粗暴处理HTTPS证书检验方法
2020-02-18 14:13 1007最近在做Flutter项目到了遇到一个无解的事情,当使用Ima ... -
flutter 获取屏幕宽度高度 通知栏高度等屏幕信息
2019-07-27 08:39 1368##MediaQuery MediaQuery.of(con ... -
关于flutter RefreshIndicator扩展listview下拉刷新的问题
2019-07-10 19:40 1158当条目过少时listview某些嵌套情况下可能不会滚动(条目 ... -
flutter listview 改变状态的时候一直无限添加
2019-07-10 16:01 817setstate的时候会一直无限的调用listview.bui ... -
Flutter Android端启动白屏问题的解决
2019-07-09 00:51 1548问题描述 Flutter 应用在 Android 端上启动时 ... -
Flutter中SnackBar使用
2019-07-08 23:43 800底部弹出,然后在指定时间后消失。 注意: build(Bui ... -
Flutter 之点击空白区域收起键盘
2019-07-08 18:43 1806点击空白处取消TextField焦点这个需求是非常简单的,在学 ... -
Flutter 弹窗 Dialog ,AlertDialog,IOS风格
2019-07-08 18:04 1403import 'package:flutter/mate ... -
flutter ---TextField 之 输入类型、长度限制
2019-07-08 14:30 2362TextField想要实现输入类型、长度限制需要先引入impo ... -
【flutter 溢出BUG】键盘上显示bottom overflowed by 104 PIXELS
2019-07-08 11:13 1601一开始直接使用Scaffold布局,body:new Colu ... -
解决Flutter项目卡在Initializing gradle...界面的问题
2019-07-07 12:53 907Flutter最近很火,我抽出了一点时间对Flutter进行了 ... -
关于android O 上 NotificationChannel 的一些注意事项
2019-07-04 11:47 954最近在适配android O,遇到个问题,应用中原本有设置界面 ...
相关推荐
在Android开发中,DataBinding库是Google推出的一种官方数据绑定框架,它可以...以上就是关于“android官方数据绑定框架DataBinding使用(2)”的主要内容,通过实际项目实践,你将能更好地理解和运用这一强大的工具。
总结,Android DataBinding框架通过数据绑定和表达式语言,极大地简化了UI和数据模型之间的交互,降低了Android开发的复杂度。通过学习和熟练掌握DataBinding,开发者可以构建更加高效、易于维护的Android应用。
在Android开发中,数据绑定(Data Binding)是一个强大的框架,它允许开发者将界面UI元素直接绑定到应用的数据源,从而简化了代码,提高了可读性和维护性。本示例将详细解析如何在Android项目中使用Data Binding库,...
在Android应用开发中,数据绑定框架(Data Binding Library)是一个强大的工具,它简化了UI与数据模型之间的交互,使得开发者可以更加专注于业务逻辑,而不是繁琐的事件处理和数据同步。本教程将指导你如何利用数据...
Android DataBinding库是Google推出的一种数据绑定框架,它旨在简化Android应用中的UI绑定,特别是对于MVVM(Model-View-ViewModel)设计模式的实现。双向绑定是DataBinding库的一个核心特性,它允许视图(View)和...
android-databinding框架设计思想与Google官方的数据绑定框架类似,主要过程是通过解析XML布局文件,然后根据绑定配置来设置对应的数据。该框架使用了libgdx游戏引擎封装的XmlReader来解析XML文件,这在效率和使用...
- 数据绑定框架支持一套丰富的表达式语言,可以在布局文件中进行简单的计算、逻辑判断和方法调用。 - 可以使用`?`操作符进行条件判断,`&`和`|`进行逻辑运算,`+`进行字符串拼接等。 3. **双向数据绑定** - 使用...
总结来说,双向绑定MVVM Databinding在Android开发中提供了强大的数据管理能力,它简化了UI和数据模型之间的交互,使得开发者可以更加专注于业务逻辑,而不是繁琐的界面更新代码。通过合理利用Databinding库,我们...
Android MVVM 框架 - 数据绑定 Android MVVM 框架是 Android 应用程序中的一种软件架构模式,它使用 Model-View-ViewModel(MVVM)模式来分离业务逻辑、用户界面和数据绑定。MVVM 模式的核心思想是将业务逻辑从...
在这个名为"Android-CFramework基于DataBinding的一个基本框架网络层使用okHttp"的项目中,开发者构建了一个使用Data Binding和OkHttp的框架,旨在提供高效且灵活的网络通信能力。 Data Binding库引入了一种声明式...
在Android开发中,数据绑定(Data Binding)是一个强大的框架,它允许开发者更加直观地将UI组件与业务数据关联起来,从而简化代码并提高可维护性。这个Demo程序旨在展示数据绑定和事件绑定的基本用法,帮助开发者...
Android DataBinding 是Google推出的一种强大的数据绑定框架,用于简化Android应用中的UI逻辑处理。这个"Android DataBinding Demo"是作者创建的一个示例项目,旨在演示DataBinding库在实际开发中的应用。通过分析这...
综上所述,Android DataBinding框架为开发者提供了一种高效、简洁的方式来实现数据绑定,是构建现代化Android应用的重要工具。结合MVVM设计模式,它能帮助你编写出更加结构化、可维护的代码。在实际项目中,如...
在Android开发中,DataBinding库是一个非常重要的组件,它能够帮助开发者更加简洁、高效地处理UI与数据之间的绑定。这个名为"Android-一些DataBinding相关的工具类"的资源集,显然是为了提供一些辅助方法和扩展,以...
DataBinding是Android SDK提供的一种框架,用于在XML布局文件中直接绑定数据到UI组件,避免了在Activity或Fragment中手动设置UI元素的值。这使得视图和数据模型之间的关系更加清晰,降低了耦合度。 要开始使用...
Android的数据绑定库是Google提供的一个官方支持的库,它引入了一种声明式编程方式,允许开发者在XML布局文件中定义表达式和操作,这些表达式会自动绑定到对应的Java对象上。这减少了手动设置UI组件属性的代码,...
Android的官方Data Binding库提供了对MVVM的支持,使得数据绑定变得更加简单和直观。 **MVVM架构介绍** MVVM模式的核心理念是解耦视图(View)和业务逻辑(ViewModel)。在Android中,View通常指的是Activity或...
DataBinding库是Google推出的一种框架,它可以将XML布局文件中的UI元素直接绑定到Java对象的属性上,使得UI的更新可以直接由数据模型驱动,避免了繁琐的findViewById操作。它的核心思想是MVVM(Model-View-ViewModel...