Anroid数据绑定框架DataBinding,堪称解决界面逻辑的黑科技
原文链接:http://www.jianshu.com/p/2d3227d9707d
去年谷歌 I/O大会上介绍了一个非常厉害的新框架DataBinding, 数据绑定框架给我们带来了很大的方便,以前我们可能需要在每个Activity里写很多的findViewById,不仅麻烦,还增加了代码的耦合性,如果我们使用DataBinding,就可以抛弃那么多的findViewById,省时省力。说到这里,其实网上也有很多快速的注解框架,但是注解框架与DataBinding想比还是不好用,而且官网文档说DataBinding还能提高解析XML的速度,其实DataBinding的好用,不仅仅体现在可以省去使用很多啰嗦findViewById。(看到这里是不是有点小激动呢,lz看到这里也是异常的激动呢)还有很多。往下看你就会明白的。
在介绍DataBinding之前,肯定是要先学会搭建使用它的环境。鉴于是去年发布的,现在大家AS的版本估计都是在1.5版本以上了(lz转载这个博客时使用的是2.2),就在1.5版本上搭建和介绍吧,1.5之前大家可以在网上搜索,因为我看网上大多数是介绍的1.3的使用方法,还没有很多对于1.5之后环境搭建的方法。(废话说这里接下来进入正题
)。
![吐舌头](http://static.blog.csdn.net/xheditor/xheditor_emot/default/tongue.gif)
环境搭建:
Android的Gradle插件版本不低于1.5.0-alpha1;
classpath'com.android.tools.build:gradle:1.5.0'
然后修改对应模块(Module)的build.grade:
注意
:Android studio的版本一定要大于1.3,而且Android Studio目前对于binding对象没有自动代码提示,只会在编译时进行检查。1.3及以前的版本对于环境的搭建,可能有点麻烦。(1.3环境搭建方法,网上多的是)
基础展示:
我们在具体讲解之前,先用一个简单的小列子来学习一下基础并展示DataBinding的巨大魅力,估计就会被其简单的特性所吸引哦。
package cn.edu.niit.test_databinding; /** * Created by zhdk on 2016/10/20. */ public class User { private String name; private String age; public User(String name, String age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
![大笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="cn.edu.niit.test_databinding.User" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.age}" /> </LinearLayout> </layout>
看到这里,可能有的人就开始有点迷糊了,没有给控件定义id,而是用了@{}方法,到底是怎么回事?先不忙,一会再来一一解释,
我们再来看看怎么把值传进去的,在Activity中是怎样使用的。
package cn.edu.niit.test_databinding; import android.databinding.DataBindingUtil; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import cn.edu.niit.test_databinding.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); User user = new User("zhdk", "21"); binding.setUser(user); } }看到这里是不是感觉Activity里面的代码很简洁,很清爽,没有了初始化fingdViewById,然后再去setText(),就仅仅添加了
两行代码。
运行结果肯定也不用说了:
基础解释:
布局生命
列子我们介绍完了,对于列子中出现的一些新东西,有必要解释一下,java bean那里就不解释了,只要是有点基础的朋友应该都懂,我们就从布局文件讲起。相比以前的xml,根节点由具体的某个layout(比如LinearLayout变成了layout),里面包括了data节点和传统的视图。这里的data节点就像是链接view和modle的桥梁。在这个data节点中声明一个variable变量,那值就可以轻松的传到布局文件来了。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <!--type声明的就是我们用户实体类User,一定要写全,带着包名--> <data> <variable name="user" type="cn.edu.niit.test_databinding.User" /> </data>
........
</layout>
TextView中的@{user.name}就是把这个user中的名字展示出来,age同样如此。
绑定variable
虽然在布局文件中对应上了,但是值是怎么传进去的呢?这就是我们要讲的Activity中的两行代码了,它把实体类和布局文件进行了绑定。修改MainActivity中的onCreate,用DataBindingUtil.setContentView();来代替setContentView();然后创建一个user对象,通过binding.setUser(user);与variable进行绑定。
高级用法
import用法:
其实data节点也是支持import用法的,比如:
<data> <import type="cn.edu.niit.test_databinding.User" /> <variable name="user" type="User" /> </data>这里需要注意的是:import并不能像java一样可以 import xx.xxx.*,必须具体写清楚要导入的类名。
类名相同
到这里你可能会问如果import了两个相同名称的类咋办?别怕,人家想的很周到,可以起个别名或者昵称的:
<data> <import alias="MyUser" type="cn.edu.niit.test_databinding.User" /> <import type="cn.edu.niit.detal.test_databinding.User" /> <variable name="user" type="User" /> <variable name="myUser" type="MyUser" /> </data>
变量定义高级用法
在上面,我们学会了如何在xml中定义一些简单的变量。我们没有定义像List、Map等这样的集合变量。那这种集合变量该如何定义呢?其实定义的方式和我们上面的基本一致,区别就在于我们还需要为它定义key的变量,例如:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <import type="java.util.ArrayList" /> <import type="java.lang.String" /> <variable name="list" type="ArrayList<String>" /> <!--泛型的支持会在编译时期报红线,但是是可以直接运行的 但是需要通过转义字符才行,如:<数据类型> 或者<数据类型>--> <import type="java.util.Map" /> <variable name="map" type="Map<String,String>" /> <variable name="arrays" type="String[]" /> </data> <!--我们需要展示的布局--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{list[0]}" /> <!--List集合既可以和数组一样通过索引获取值list[index]方式,也可以调用API--> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{list.get(1)}" /> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{map[`name`]}" /> <!--Map集合既可以通过map[key]的方式,也可以通过调用API--> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{map.get(`age`)}" /> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{arrays[0]}" /> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="@{arrays[1]}" /> </LinearLayout> </layout>注意:泛型的支持会在编译时报红线,但是是可以直接运行的,但是需要通过转义字符才行。
Activity中的代码:
package cn.edu.niit.test_databinding; import android.databinding.DataBindingUtil; import android.databinding.tool.CompilerChef; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import cn.edu.niit.test_databinding.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); ArrayList<String> list = new ArrayList<>(); list.add("first"); list.add("second"); binding.setList(list); Map<String, String> map = new HashMap<>(); map.put("name", "zhangsan"); map.put("age", "40"); binding.setMap(map); String[] arrays = {"lisi", "laowang"}; binding.setArrays(arrays); } }关于UI上的操作全部放在xml文件里面,是不是感觉方便了许多了呢?
布局引用文件(includes):
变量可以传递到布局文件引用的布局文件中
<?
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
>
事件绑定:
如果对控件进行点击事件处理,只需在<data>标签里面添加<variable>然后设置自己的点击事件,type类型指定为:android.view.View.OnClickListener,具体实现如下:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="myClick" type="android.view.View.OnClickListener" /> </data> <Buttonandroid:id="@+id/btn1"android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{myClick}" android:text="点击" /></layout>
在代码中实现点击事件:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainBinding binding = DataBindingUtil.setContentView(this, R.layout.main); binding.setMyClick(new View.OnClickListener() { @Override public void onClick(View view) { //要做的事 } }); }也可以通过id来实现绑定:
binding.btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } });
表达式:
在xml中也是支持表达式的:
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{error ? "error" : "ok"}'/>
这是一个布尔值的使用。
下面我们就来看看表达式支持的一下语法和不支持的语法
支持的表达式:
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
ok,关于DataBinding的基础部分差不多也就这样了,当然,还有很多高级的用法,大家可以查阅更多的资料去学习。