在上一篇文章Android Databinding(初识),介绍了Databinding及代码示例,在这里将从代码的层次上进行Databinding的详细讲解。
本章节主要讲解Data binding的xml文件的代码书写规范。下面直接上硬货。
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto">
<data>
<import type="wshuttle.com.testmvvm.bean.UserInfo"/>
<import type="android.view.View"/>
<variable
name="imageUrl"
type="android.databinding.ObservableInt" />
<variable name="userInfo" type="UserInfo" >variable>
<variable name="show" type="android.databinding.ObservableBoolean" >variable>
<variable
name="myEventHandler"
type="wshuttle.com.testmvvm.ui.MainActivity.MyEventHandler">variable>
<variable
name="orderInfo"
type="wshuttle.com.testmvvm.bean.OrderInfo" />
data>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:background="@color/bg_color"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"
android:background="@color/theme_color">
android.support.v7.widget.Toolbar>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@{String.valueOf(userInfo.id)}" />
<EditText
android:cursorVisible="true"
android:textCursorDrawable="@drawable/color_cursor"
android:layout_width="match_parent"
android:textColor="@color/text_color"
android:id="@+id/username"
android:layout_height="wrap_content"
android:text="@={userInfo.name}" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@={userInfo.type}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:onClick="@{(view) ->myEventHandler.getUser(userInfo)}"
android:id="@+id/btnGetName"
android:text="获取用户信息" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:onClick="@{myEventHandler::onClick}"
android:id="@+id/btnGetType"
android:text="获取车主姓名" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@{orderInfo.orderid}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@{orderInfo.rescueName}" />
<com.facebook.drawee.view.SimpleDraweeView
android:layout_width="50dp"
android:layout_height="50dp"
android:visibility="@{show.get()?View.VISIBLE:View.GONE}"
fresco:image_url="@{imageUrl.get()}"
fresco:roundAsCircle="true"
/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
fresco:image_url="@{imageUrl.get()}"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="16dp"
android:id="@+id/listView"
/>
LinearLayout>
layout>
第一眼看去也许跟原先的布局文件与很大变化,但是细看变化之处在于节点的变化,内层的布局与原布局文件是一模一样的。下面针对布局文件中的节点进行解释。
一、layout
在这里,不是以相对布局等布局方式作为根节点,而是以layout作为根节点,它的作用是申明它是一个data binding的布局文件,申明后as会自动编译生成一个ActivityMainBinding(首字母大写,加后缀Binding)的Java类,我们在Activity操作的实际上就是这个Java类。
我们先说一说这个根节点下面引入的命名空间,第一个Android就无需解释了,第二个http://schemas.android.com/apk/res-auto是Data binding进行一些数据属性绑定所需要用到的命名空间,fresco只是一个别名而已无需在意,我的建议是每次如果需要把该布局设置成data binding布局的话,根节点上就添加这样一个命名空间,方便之后的调用。
二、data
此节点是整个布局上最大的变化之处,data节点从字面意思就明白我们数据就在这里了,实际上data节点也就是整个布局文件的数据源,data节点的内容就类似于Java类中引入包以及定义变量的意思。下面说说data下面各个节点的意义。
import:跟Java类一样,就相当于引入Java包,其中有的常用属性有,type:类的路径,需要有包名,alias:为该引入的包去别名(主要为了区分引入两个相同的类名的冲突)。
variable:相当于定义变量,其中常用的属性有,name:变量的名称,type:变量的类型(基本类型,Java类或者Data
bingding类型等)。
下面就本例子下data节点进行解释,本例子下引入了项目的UserInfo,View;定义了imageUrl类型为ObservableInt,userInfo等变量。在这里解释一下ObservableInt是什么类型呢?这个类型是Data binding中定义的类型,如果你布局文件中定义的是此种类型的话,你在Activity中对这个值进行重新赋值的话,界面上会进行刷新,会在改界面上引用改变量地方进行刷新操作(具体如何操作请看),实际上还有另外一种方式可实现单向的刷新操作,imageUrl的类型可以直接为int类型,但是需要Activity调用Binding类的notifyPropertyChanged方法刷新该数据才会刷新界面,代码如下:
ActivityMainBinding bing = DataBindingUtil.setContentView(this, R.layout.activity_main);
bing.notifyPropertyChanged(BR.imageUrl);//刷新imageUrl的value
综合来讲,data下面就是定义数据的地方,只不过data binding在进行数据绑定时,实行Activity与layout实现界面更新,需要使用它自己内部定义的方法或者说写上刷新界面的方法。注意在引入类的过程中,要注意xml中有些必须转义的字符,比如说引入Map时,你直接使用Map
type="Map<String,Object>" />
三、数据以及事件绑定
这里是layout文件的重点,data binding是如何实现数据的绑定的呢?我们从上面activity_main.xml文件的源码中进行分析。在这里我们可以看见上面三个文本框的text属性的赋值,看之前我们先看看UsInfo类,这里的UserInfo的属性也使用的是Observable类型的类型,也是为了实现一种单向的绑定。看看我们的EditText的赋值操作, android:text=”@{String.valueOf(userInfo.id)}”这里由于id是int类型,我们使用String.ValueOf进行转化为String,否则会报错,text必须是要为String类型,由于两遍的类型不匹配所以这个字段只能支持一种单向的绑定,也就是Activity刷新layout;android:text=”@={userInfo.name}”就是实现的一种双向的绑定,Activity值改变会刷新数据,EditText输入文本以后会改变Activity对应的实体,如此形成绑定以后则无需再关心layout中的标签了。布局中的id与name的绑定就是数据的单向绑定与双向绑定,@{}为单向的绑定,@={}为双向的绑定。
UserInfo
package wshuttle.com.testmvvm.bean;
import android.databinding.ObservableField;
import android.databinding.ObservableInt;
/**
* Observable数据基本类型实现绑定@{}:单向绑定,@={}双向绑定,不是String类型实现双向绑定无法绑定,待解决.
* Created by yzy on 2016/9/21.
*/
public class UserInfo{
public ObservableInt id = new ObservableInt();
public ObservableField name = new ObservableField();
public ObservableField type = new ObservableField();
@Override
public String toString() {
return "UserInfo{" +
"id=" + id.toString() +
", name=" + name.toString() +
", type=" + type.toString() +
'}';
}
public UserInfo(int id, String name, String type) {
this.id.set(id);
this.name.set(name);
this.type.set(type);
}
public UserInfo() {
}
}
"match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@{String.valueOf(userInfo.id)}" />
"true"
android:textCursorDrawable="@drawable/color_cursor"
android:layout_width="match_parent"
android:textColor="@color/text_color"
android:id="@+id/username"
android:layout_height="wrap_content"
android:text="@={userInfo.name}" />
"match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color"
android:text="@={userInfo.type}" />
看完EditText的单向绑定以及双向绑定,我们再来看看其他的绑定吧。下面我们看看Data binding的事件绑定,事件的绑定在这里我是使用自定义的MyEventHandler类来处理这个单击事件(在这里我们可以直接使用onClickListener进行单击事件赋值,在这里为了体现一种data binding的可扩展性我使用的是自定义的事件处理),该类中只有两个方法一个getUser方法,参数有一个UserInfo,一个onClick方法,参数View。我们看布局文件中Button,第一个android:onClick=”@{(view) ->myEventHandler.getUser(userInfo)}”,这里使用的是lambda表达式进行事件的绑定,在这里前面的(view)表示的事件本身,myEventHandler是声明的变量,我们调用myEventHandler.getUserInfo的方法来处理该单击事件,并且将userInfo的参数作为形参;第二个button, android:onClick=”@{myEventHandler::onClick}”直接使用调用的方法,由于它无需传递参数,所以这里就使用::调用方法,调用此方法默认是会把本身的view作为参数传递到方法中。注意:如果没有参数的话,自定义的事件监听的方法也必须要有view作为参数传递进去,否则会报错。
myEventHandler
/**
* 自定义事件Handler
*/
public class MyEventHandler {
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnGetType: {
Toast.makeText(MainActivity.this, orderInfo.getRescueName(), Toast.LENGTH_SHORT).show();
break;
}
}
}
public void getUser(UserInfo userInfo) {
Toast.makeText(MainActivity.this,"id:" + userInfo.id.get() + ",name:" + userInfo.name.get() + ",type:" +userInfo.type.get() ,Toast.LENGTH_SHORT).show();
}
}
下面我们再看一下,在布局文件中的逻辑判断,这里我们界面上实现的简单的逻辑判断是通过根据show的值显示隐藏图片。 在这里android:visibility=”@{show.get()?View.VISIBLE:View.GONE}”,show是ObservableBoolean类型的,它实际上是一个类,所以通过.get获取它的值,在这里我们可以看见这只是一个简单的?语句操作符,实现了简单的image显示隐藏,实际上可以通过更加复杂的语句进行判断,执行逻辑操作。在这个标签控件下我们还可以看见一个fresco这不是引用的data binding需要的命名空间吗?roundAsCircle是com.facebook.fresco框架(一个比较好的图片框架)自带的属性,但是image_url这明显感觉不像啊,在这里简单说一下,那是我们自己定义的属性,就如同自定义控件的attr一样,自定义属性的方法我们在下一章节进行详细讲解。
<com.facebook.drawee.view.SimpleDraweeView
android:layout_width="50dp"
android:layout_height="50dp"
android:visibility="@{show.get()?View.VISIBLE:View.GONE}"
fresco:image_url="@{imageUrl.get()}"
fresco:roundAsCircle="true"
/>
四、注意点
1、在xml中使用的过程中,有些重要的字符是需要转义的,比如>、&等等,需要转义的话可以参考Xml文件必须转义的字符。
2、自定义事件监听时,如果自定义的方法没有参数的话,也需要增加View的形参,否则编译不会通过。
3、在xml中如果需要直接使用字符串的话,需要使用 ` (英文状态下的tab上一个键)。
4、在xml中字符赋值过程中,最好不要直接使用字符进行累加显示比如说android:text=”@{你好啊
+test+哈哈哈
}”,有时会提示utf-8的问题,可能是字符大小超过限制,如果必须要的话最好使用android:text=”@{@string/nihao_string+test+@string/haha_string}”>
五、总结
在本篇文章中主要讲解的data binding在layout的语法以及结构,看完本章后可以继续查看下一章节(Android databinding详解(二)–activity解析),将具体讲解data binding在activity中的具体讲解。