android:DataBinding使用小结(一)
一、初步使用DataBinding
-
引入DataBinding
在你的app下的build.gradle中添加对DataBinding的支持
android {
...
//第一步:引入dataBinding
dataBinding {
enabled = true
}
}
- 更改你的xml布局,对dataBinding的支持
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="tsou.cn.databinding.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Frist Name" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Last Name" />
<TextView
android:id="@+id/first_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/last_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
- 在MainActivity中使用dataBinding绑定你的xml布局,并代替findviewbyid
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
User user = new User();
user.setFristName("huang");
user.setLastName("xiaoguo");
// 第三步:使用 ActivityMainBinding
/**
* Android studio会根据layout文件自动生成一个默认的Binding类,
* 类名是根据layout文件名生成的,
* 并有"Binding"后缀结束。
* 例如:activity_main.xml生成的Binding类为ActivityMainBinding
*
* 如果ActivityMainBinding,无法找到,可以先编译一下项目
*/
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
/**
* 解决问题之:findviewbyId
*/
binding.firstName.setText(user.getFristName());
binding.lastName.setText(user.getLastName());
}
二、DataBinding 绑定UI (setVariable、setXXX)
- 在xml中添加data数据绑定标签
<?xml version="1.0" encoding="utf-8"?>
<!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!--
第四步:xml数据绑定,name表示数据对象名称
type:表示包名
-->
<data>
<variable
name="user"
type="tsou.cn.databinding.bean.User"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="tsou.cn.databinding.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Frist Name" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Last Name" />
<TextView
android:text="@{user.fristName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
- 将activity中的数据绑定到xml中
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
User user = new User();
user.setFristName("huang");
user.setLastName("xiaoguo");
// 第三步:使用 ActivityMainBinding
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
/**
* 将数据绑定到xml
*/
// 方法一:(常用)
//binding.setUser(user);
//方法二:
binding.setVariable(BR.user,user);
}
}
-
其他引入数据姿势
如果用户类型要多处用到,也可以直接将之后导入进来, 这样就不用每次都指明整个包名路径了, 而java.lang.*包中的类会被自动导入,所以可以直接使用
<data>
<import type="tsou.cn.databinding.bean.User"/>
<variable
name="user"
type="User"/>
</data>
如果存在进口的类名相同的情况,可以使用别名指定别名
<data>
<import type="tsou.cn.databinding.bean.User" />
<import
alias="TwoUser"
type="tsou.cn.databinding.bean2.User" />
<variable
name="user"
type="User" />
<variable
name="twoser"
type="TwoUser" />
</data>
三、事件绑定
- 创建Presenter类
public class Presenter{
//普通方法绑定
public void onTextChanged( CharSequence s,int start,int before,int color){
user.setFristName(s.toString());
binding.setUser(user);
}
//普通方法绑定
public void onClick(View view){
Toast.makeText(MainActivity.this.getApplicationContext(),"点击了",Toast.LENGTH_LONG).show();
}
//监听器绑定,可以返回数据
public void onClickListenerBinding(User user){
Toast.makeText(MainActivity.this.getApplicationContext(),user.getLastName(),Toast.LENGTH_LONG).show();
}
}
- 在xml中传入presenter并进行绑定
<?xml version="1.0" encoding="utf-8"?><!--
第二步:在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!--
第四步:xml数据绑定,name表示数据对象名称
type:表示包名
-->
<variable
name="user"
type="tsou.cn.databinding.bean.User" />
<!--
第五步:事件绑定
name:类名
type:表示包名
-->
<variable
name="presenter"
type="tsou.cn.databinding.MainActivity.Presenter" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="tsou.cn.databinding.MainActivity">
<!--
建议使用
android:onTextChanged="@{presenter::onTextChanged}"
可以将方法的绑定和普通函数的调用或数据绑定,区分开
-->
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Frist Name"
android:onTextChanged="@{presenter.onTextChanged}" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Last Name" />
<!--
普通方法绑定
建议使用
android:onClick="@{presenter::onClick}"
可以将方法的绑定和普通函数的调用或数据绑定,区分开
-->
<TextView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{presenter.onClick}"
android:text="@{user.fristName}" />
<!--
监听器绑定,可以返回数据
-->
<TextView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->presenter.onClickListenerBinding(user)}"
android:text="@{user.lastName}" />
</LinearLayout>
</layout>
- acticity中绑定Presenter对象
binding.setPresenter(new Presenter());
- 效果如下:
四、xml中对表达式的支持
支持的运算符:
- 数学运算符: + - / * %
- 字符串拼接: +
- 逻辑运算符: && ||
- 二进制: & | ^
- 一元运算符: +
- 位运算符: >> >>> <<
- 比较: == > < >= <=
- instanceof
- ()
- 数据类型: character, String, numeric, null
- 类型转换(ClassCast)
- 方法回调(Method calls)
- 数据属性
- 数组:[]
- 三元操作符:?
例如:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:background="@{true ? @color/colorAccent : @color/colorPrimary}"
android:transitionName='@{"image_" + id}'
一些在java中常用而DataBinding xml中不支持的:
- this
- super
- new
- 泛型
空合并运算符
android:text="@{user.displayName ?? user.lastName}"
等价于
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
- view的显示和隐藏
在xml data节点下引入view
<data>
<import type="android.view.View" />
</data>
view的显示和隐藏
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="是否显示"
android:textColor="@color/colorAccent"
android:textSize="24sp"
android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />
五、include的使用
- 创建include布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!--
xml数据绑定,name表示数据对象名称
type:表示包名
-->
<variable
name="user"
type="tsou.cn.databinding.bean.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:layout_gravity="center"
android:text="@{user.fristName}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{user.lastName}" />
</LinearLayout>
</layout>
- 使用include布局并传递数据
<include
layout="@layout/include_layout"
bind:user="@{user}" />
- 效果如下
六、ViewStub使用
- ViewStub布局
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!--
xml数据绑定,name表示数据对象名称
type:表示包名
-->
<variable
name="user"
type="tsou.cn.databinding.bean.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher_round" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.imageId}" />
</LinearLayout>
</layout>
- 调用ViewStub
<ViewStub
android:id="@+id/view_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/viewstub"
bind:user="@{user}" />
- 加载viewStub
//使用viewStub
binding.viewStub.getViewStub().inflate();
七、BaseObservable数据更新监听使用
- 将javaBean继承BaseObservable
package tsou.cn.databinding.bean;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import tsou.cn.databinding.BR;
/**
* Created by Administrator on 2018/5/25 0025.
*/
//BaseObservable数据自动更新的使用
public class User extends BaseObservable {
private String fristName;
private String lastName;
private String imageUrl;
private boolean isShow;
@Bindable
public boolean getIsShow() {
return isShow;
}
public void setIsShow(boolean show) {
isShow = show;
notifyPropertyChanged(BR.isShow);
}
@Bindable
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
notifyPropertyChanged(BR.imageUrl);
}
@Bindable
public String getFristName() {
return fristName;
}
public void setFristName(String fristName) {
this.fristName = fristName;
notifyPropertyChanged(BR.fristName);
}
@Bindable
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
注意:
1、首先当前类继承BaseObservable
2、对于get方法添加@Bindable注解
3、引入BR.lastName等报错时,需要对项目先进行一下修复
- 布局中进行监听
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 Frist Name"
android:onTextChanged="@{presenter::onTextChanged}" />
- 调用方法
public class Presenter {
//普通方法绑定
public void onTextChanged(CharSequence s, int start, int before, int color) {
user.setFristName(s.toString());
//此时不需要再次手动进行更新数据对象了
// binding.setUser(user);
}
}
八、ObservableField数据监听的使用
ObservableField是为了解决一个数据类中不需要所有的数据都进行监听时代替BaseObservable,让类当前类不需要继承BaseObservable也不需要重新notifyPropertyChanged方法
- 在数据类中
/**
* 在单个或者比较少的数据需要监听时使用ObservableField
* (ObservableBoolean,ObservableChar,ObservableInt,ObservableParcelable.....)
*/
private ObservableField<Boolean> isShow = new ObservableField<>();
public ObservableField<Boolean> getIsShow() {
return isShow;
}
public void setIsShow(boolean show) {
/**
* 如果是Observable*类型设置数据需要使用set
*/
this.isShow.set(show);
}
- 布局中使用
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="是否显示"
android:textColor="@color/colorAccent"
android:textSize="24sp"
android:visibility="@{user.isShow ? View.VISIBLE:View.GONE }" />
- 更新数据
public class Presenter {
//普通方法绑定
public void onTextChanged(CharSequence s, int start, int before, int color) {
user.setFristName(s.toString());
//这里直接更改数据就好
user.setIsShow(!user.getIsShow().get());
// binding.setUser(user);
}
}
九、ObservableArrayList和ObservableArrayMap的使用
- 在数据类中
private ObservableArrayList<String> nums;
private ObservableArrayMap<String,String> maps;
public ObservableArrayList<String> getNums() {
return nums;
}
public void setNums(ObservableArrayList<String> nums) {
this.nums=nums;
}
public ObservableArrayMap<String, String> getMaps() {
return maps;
}
public void setMaps(ObservableArrayMap<String, String> maps) {
this.maps = maps;
}
- 布局中使用
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{user.nums[0]}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text='@{user.maps["name"]}' />
- 添加数据
全局集合对象
private ObservableArrayList<String> nums = new ObservableArrayList<>();
private ObservableArrayMap<String, String> maps = new ObservableArrayMap<>();
在绑定数据之前添加集合对象
//ObservableArrayList和ObservableArrayMap的使用:添加对象
user.setNums(nums);
user.setMaps(maps);
/**
* 将数据绑定到xml
*/
// 方法一:
//binding.setUser(user);
//方法二:
binding.setVariable(BR.user, user);
更改数据
nums.add("我是ObservableArrayList");
maps.put("name", "我是ObservableArrayMap");
十、BindingAdapter的使用
- 使用BindingAdapter构建图片加载方法
/**
* Created by Administrator on 2018/5/30 0030.
*/
public class ImageUtil {
@BindingAdapter({"url"})
public static void loadImage(ImageView view, String url) {
Glide.with(UIUtils.getContext()).load(url).into(view);
}
}
- xml文件绑定数据
<?xml version="1.0" encoding="utf-8"?><!--
在布局中跟节点添加layout
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<!--
xml数据绑定,name表示数据对象名称
type:表示包名
-->
<variable
name="user"
type="tsou.cn.databinding.bean.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--
这里的bind:url="@{user.imageUrl}"即为调用 @BindingAdapter({"url"}绑定的数据
-->
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
bind:url="@{user.imageUrl}"
android:src="@mipmap/ic_launcher_round" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.imageUrl}" />
</LinearLayout>
</layout>
- 添加Url数据
user.setImageUrl("https://unsplash.it/200/200?random&10");
-
BindingAdapter更加强大的一点是可以覆盖Android原先的控件属性。例如,可以设定每一个TextView的文本都要加上后缀:“ - 追加的数据”
注意:这里追加数据的TextView必须使用数据绑定来填充数据,否则无效
@BindingAdapter("android:text")
public static void setText(TextView view, String text) {
view.setText(text + "-追加的数据");
}
十一、BindingConversion使用
dataBinding还支持数据进行转换,或者进行类型转换。
与BindingAdapter类似,以下方法会将布局文件中所有以@{String}方式引用到的String类型变量加上后缀-conversionString
@BindingConversion
public static String conversionString(String text) {
return text + "-conversionString";
}
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='@{"xxx"}'
android:textAllCaps="false"/>
可以看到,对于TextView来说,BindingAdapter和BindingConversion同时生效了,而BindingConversion的优先级要高些。此外,BindingConversion也可以用于转换属性值的类型。
看以下布局,此处在向background和textColor两个属性赋值时,直接就使用了字符串,按正常情况来说这自然是会报错的,但有了BindingConversion后就可以自动将字符串类型的值转为的需要Drawable状语从句:Color了
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background='@{"红色"}'
android:padding="20dp"
android:text="红色背景蓝色字"
android:textColor='@{"蓝色"}'/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background='@{"蓝色"}'
android:padding="20dp"
android:text="蓝色背景红色字"
android:textColor='@{"红色"}'/>
@BindingConversion
public static Drawable convertStringToDrawable(String str) {
if (str.equals("红色")) {
return new ColorDrawable(Color.parseColor("#FF4081"));
}
if (str.equals("蓝色")) {
return new ColorDrawable(Color.parseColor("#3F51B5"));
}
return new ColorDrawable(Color.parseColor("#344567"));
}
@BindingConversion
public static int convertStringToColor(String str) {
if (str.equals("红色")) {
return Color.parseColor("#FF4081");
}
if (str.equals("蓝色")) {
return Color.parseColor("#3F51B5");
}
return Color.parseColor("#344567");
}
十二、Array、List、Set、Map …
dataBinding也支持在布局文件中使用数组,Lsit,Set和Map,且在布局文件中都可以通过list[index]形式来获取元素。
而为了和变量标签的尖括号区分开,在声明Lsit 之类的数据类型时,需要使用尖括号的转义字符。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="java.util.List" />
<import type="java.util.Map" />
<import type="java.util.Set" />
<import type="android.util.SparseArray" />
<variable
name="array"
type="String[]" />
<variable
name="list"
type="List<String>" />
<variable
name="map"
type="Map<String, String>" />
<variable
name="set"
type="Set<String>" />
<variable
name="sparse"
type="SparseArray<String>" />
<variable
name="index"
type="int" />
<variable
name="key"
type="String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main7Activity">
<TextView
···
android:text="@{array[1]}" />
<TextView
···
android:text="@{sparse[index]}" />
<TextView
···
android:text="@{list[index]}" />
<TextView
···
android:text="@{map[key]}" />
<TextView
···
android:text='@{map["leavesC"]}' />
<TextView
···
android:text='@{set.contains("xxx")?"xxx":key}' />
</LinearLayout>
</layout>
十三、资源引用
dataBinding支持对尺寸和字符串这类资源的访问
- dimens.xml
<dimen name="paddingBig">190dp</dimen>
<dimen name="paddingSmall">150dp</dimen>
- strings.xml
<string name="format">%s is %s</string>
<data>
<variable
name="flag"
type="boolean" />
</data>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@{flag ? @dimen/paddingBig:@dimen/paddingSmall}"
android:text='@{@string/format("leavesC", "Ye")}'
android:textAllCaps="false" />
其他注意知识点
-
默认数据
由于@{userInfo.name}在布局文件中并没有明确的值,
所以在预览视图中什么都不会显示,
不便于观察文本的大小和字体颜色等属性,
此时可以为之设定默认值(文本内容或者是字体大小等属性都适用),
默认值将只在预览视图中显示,且默认值不能包含引号
android:text="@{user.fristName,default=这是默认数据}"
-
自定义实例名称
每个数据绑定布局文件都会生成一个绑定类, ViewDataBinding的实例名是根据布局文件名来生成, 将之改为首字母大写的驼峰命名法来命名, 并省略布局文件名包含的下划线。 控件的获取方式类似,但首字母小写。 也可以通过如下方式自定义ViewDataBinding的实例名
<data class="CustomBinding">
</data>
Demo地址:https://download.csdn.net/download/huangxiaoguo1/10454497
推荐阅读
-
android使用DataBinding来设置空状态
-
Android开发笔记之:一分钟学会使用Logcat调试程序的详解
-
使用Python对IP进行转换的一些操作技巧小结
-
Android编程使用加速度传感器实现摇一摇功能及优化的方法详解
-
Android之使用Android-query框架开发实战(一)
-
Android中使用Alarm的方法小结
-
Android Fragment中使用SurfaceView切换时闪一下黑屏的解决办法
-
Android编程使用Fragment界面向下跳转并一级级返回的实现方法
-
Android PopupWindow使用方法小结
-
Android 使用SharePerference判断是否为第一次登陆的实现代码