Android数据绑定框架能够帮助我们实现界面和逻辑代码的解耦合,同时实现代码自动生成机制,避免使用反射影响运行效率.
简单一点说,数据绑定框架能够帮助我们将实体类映射到布局文件中,帮我们将注意力从界面显示移到功能逻辑开发.
最新的数据绑定框架系统需求如下:
Android minSDKVersion >= 7 Android Gradle Plugin >= 1.5-alpha1 Android Studio >= 1.3
如果你希望在使用数据绑定框架,那么需要在module对应的 build.gradle
文件中,加入以下配置项:
1 android { 2 .... 3 dataBinding { 4 enabled = true 5 } 6 }
需要注意:如果你某个module的依赖库使用了数据绑定,那么这个module的配置文件中也应该开启数据绑定框架.
我们先看看传统的布局文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 <TextView android:layout_width="wrap_content" 7 android:layout_height="wrap_content" 8 android:text="firstName"/> 9 <TextView android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:text="lastName"/> 12 </LinearLayout>
对于这种文件,每一个标签会对应一个View,而在数据绑定框架中,之前的文件不会发生太大的变化:
1 <?xml version="1.0" encoding="utf-8"?> 2 <layout xmlns:android="http://schemas.android.com/apk/res/android"> 3 <data> 4 <variable name="user" type="com.example.User"/> 5 </data> 6 <LinearLayout 7 android:orientation="vertical" 8 android:layout_width="match_parent" 9 android:layout_height="match_parent"> 10 <TextView android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:text="@{user.firstName}"/> 13 <TextView android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="@{user.lastName}"/> 16 </LinearLayout> 17 </layout>
可以看到,之前的布局文件样式并没有发生任何改变,只是将之前的根节点改成了layout标签的一个子节点,并增加了一个data标签作为他的兄弟节点.
layout标签用于声明当前布局文件是一个实现了布局绑定的布局文件,方便代码自动生成工具进行解析生成代码.
data标签用于声明当前可能使用到的变量和类型,将在下面做详细介绍.
data标签有两种类型的子标签,分别是 import
和 variable
.
1.import
import
标签用于声明Java类的引入关系,就跟在jsp中的类引入一样,Android数据绑定框架也需要根据类的包名等信息才能够确定类的调用关系
ps:同java一样,默认引入了 java.lang.*;
(毕竟本来就是生成一个Java文件)
1 <import type="android.view.View"/>
引用类型之后,我们就可以调用他的静态属性和方法
1 <TextView 2 android:text="@{user.lastName}" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
如果类名发生冲突,我们可以使用别名进行引入
1 <import type="android.view.View"/> 2 <import type="com.example.real.estate.View" 3 alias="Vista"/>
2.variable
variable
标签用于声明布局文件中的变量,我们知道数据绑定框架可以访问Java实体类中的信息,而variable标签中定义的对象就是框架会访问的实体类.
1 <variable name="user" type="com.example.User"/>
在上面的标签中,我们定义了一个类型为 com.example.User
的变量,他的变量名为user,所以在之后的布局文件中我们可以通过user这个变量名去使用User对象的数据
1 <TextView android:layout_width="wrap_content" 2 android:layout_height="wrap_content" 3 android:text="@{user.firstName}"/>
在这里,我们通过 @{}
的语法访问user的firstName的属性,并将其赋值给TextView的 android:text
属性.
对于一个普通的Java对象(POJO),他的代码类似如下:
1 public class User { 2 public final String firstName; 3 public final String lastName; 4 public User(String firstName, String lastName) { 5 this.firstName = firstName; 6 this.lastName = lastName; 7 } 8 }
对于JavaBeans对象,他的代码类似如下:
1 public class User { 2 private final String firstName; 3 private final String lastName; 4 public User(String firstName, String lastName) { 5 this.firstName = firstName; 6 this.lastName = lastName; 7 } 8 public String getFirstName() { 9 return this.firstName; 10 } 11 public String getLastName() { 12 return this.lastName; 13 } 14 }
在上面的代码中,对于前一种 firstName和lastName字段都是public的,所以我们可以直接访问,而对于后一种对象,firstName和lastName对象都是private的, 所以我们需要通过getter访问器进行访问
不过对于数据绑定框架而言,这两者是等价的,在自动代码生成的时候,系统会自动根据实体类生成对应的代码.例如在前一种代码中,会自动访问firstName自动,而在后一种代码中会访问getFirstName方法.
除了这两种访问形式以外,如果实体类中其实是一个叫做firstName()的方法,那么他也会被自动识别调用.
我们可以看到实现了数据绑定的布局文件和传统的布局文件是有区别的,因此我们不能够直接像以前那样进行界面实例化.
假如我们这里有一个实现了数据绑定的main_activity.xml布局文件
1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); 5 User user = new User("Test", "User"); 6 binding.setUser(user); 7 }
通过上面的代码,你可以发现在Activity界面上自动显示了Test User的文本,但是其实我们自己并没有去设置TextView的显示规则,一切都是依赖数据绑定框架实现.
原来DataBinding框架通过自动代码生成创建了一个MainActivityBinding类,在这个类中,根据布局文件中的设置自定进行赋值,从而达到正确的界面显示效果.
除此之外,你也可以直接使用MainActivityBinding获取到ViewDataBinding对象:
1 MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater()); 2 //or 3 ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); 4 //or 5 ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
默认情况下,一个数据绑定类的类名是通过布局文件的名字按照驼峰原则进行首字母大写转换再加上一个Binding后缀表明这是数据绑定类.例如这里main_activity.xml的数据绑定类是MainActivityBinding类.他被默认放置在module的一个叫做databinding的子包中.
如果你想自定义数据绑定类的类名或存放路径,直接修改data标签中的class属性即可.
1 <data class="ContactItem"> 2 ... 3 </data>
这里会将数据绑定类重新命名为ContactItem
1 <data class=".ContactItem"> 2 ... 3 </data>
这里会将数据绑定类重新命名为ContactItem,同时前面的 .
代表一个相对与module包名的路径,也就是说它会直接被存放在module包下
1 <data class="com.example.ContactItem"> 2 ... 3 </data>
这里直接给出了完整的包名和类名.
这里简单介绍了如何配置Android数据绑定框架,以及如何在代码中使用它.通过上面的样例,我们可以看出Android数据绑定是希望把界面显示和数据绑定在一起,根据变量属性指定每一个布局的相关属性. 从而避免我们在代码中通过获取View实例来设置界面显示效果,如果界面显示逻辑发生变化,也只需要更改布局文件的相关表达式即可,在一定程度上的确是降低了逻辑和显示的耦合程度(虽然是靠生成一系列布局文件达到的,也就是说布局和实体类被耦合在了一起,不过这一块的代码是使用工具自动生成的),能够降低我们开发成本.
当然从上面的代码中我只是简单介绍了界面显示逻辑的绑定规则,Android的绑定框架还支持对事件以及自定义属性的实现,这会在接下来的文章里做具体描述,入门篇就到这里吧.