Android_Databinding使用整理
自从使用android databinding之后,个人觉得还是很有必要掌握,相比于传统方式,android databinding的优势有如下:
- 解决了数据直接去绑定ui
- 解决ui可以直接绑定数据
- 适用于MVVM框架
- 提高了开发效率,减少了Activity、Fragment、View、Adapter等刷新的代码
- 通过自定义属性,可以封装自己的布局代码
使用:
在app对应的model中build.gradle
加上这句:
android {
....
dataBinding {
enabled = true
}
}
实体在xml中使用:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="user"
type="com.single.androiddatabing.bean.User" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{user.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{String.valueOf(user.age)}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>
</layout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User();
user.age = 12;
user.name = "zhangsan";
viewDataBinding.setUser(user);
}
xml中通过layout根标签去添加布局,然后在data标签中定义好实体,在view中使用实体的时候用@{}来获取实体的数据,在代码中就会动态生成一个ActivityMainBinding
类,代码中的setUser
就是通过xml布局中name来生成的方法。
xml中import关键字使用:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="user"
type="com.single.androiddatabing.bean.User" />
<import type="android.view.View" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{user.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{String.valueOf(user.age)}"
android:visibility="@{user.age>10?View.VISIBLE:View.GONE}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>
</layout>
上面的例子中判断age>10才会显示,否则不显示。显示的时候,导入了View这个类,在第一个例子中,其实本应该导入String类型的,但是在dataBinding中除了基本类型不导入外,其余的都需要导入,其实这里还可以判断textColor、字体大小等等,这里就不一一举例了,大家在实际项目中慢慢使用、体会。
上面的例子中,导入的是系统提供的View类,dataBinding也支持自己写的类导入,下面写个简单的例子:
package com.single.androiddatabing.utils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by xiangcheng on 18/12/28.
*/
public class FormatUtils {
//定义了一个简单的格式化时间的方法
public static String formatTime(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
return simpleDateFormat.format(date);
}
}
布局添加import
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="date"
type="java.util.Date" />
<import type="com.single.androiddatabing.utils.FormatUtils" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{FormatUtils.formatTime(date)}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</layout>
上面自定义工具类的方式看到了没,定义好工具类,直接调他们的方法,记得不要忘记在代码中调用:
ActivityImport1Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_import1);
viewDataBinding.setDate(new Date());
onClick事件使用lambda方式
- 双冒号形式调用:
public class OnclickEvent {
public void onClickFriend(View view) {
if (view.getId() == R.id.textView) {
Log.d("TAG", "点击了");
Toast.makeText(view.getContext(), "button1被点击了", Toast.LENGTH_LONG).show();
} else if (view.getId() == R.id.button) {
Log.d("TAG", "点击了");
Toast.makeText(view.getContext(), "button2被点击了", Toast.LENGTH_LONG).show();
}
}
}
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="onclickEvent"
type="com.single.androiddatabing.event.OnclickEvent" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<Button
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{onclickEvent::onClickFriend}"
android:text="button1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{onclickEvent::onClickFriend}"
android:text="Button2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>
</layout>
不要忘记在代码中设置onclickEvent
:
ActivityOnclick1Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_onclick1);
viewDataBinding.setOnclickEvent(new OnclickEvent());
上面形式设置onclickEvent灵活性不是很高,个人不是很喜欢这种方式,下面再介绍一种。
- lambda形式
public class OnclickEvent {
public void runTask(Task task) {
task.run();
}
public void runTask(View view, Task task) {
Toast.makeText(view.getContext(), "执行了传view的runTask", Toast.LENGTH_SHORT).show();
task.run();
}
public void runTask(View view, Task task, boolean isRun) {
Toast.makeText(view.getContext(), "执行了传view的runTask", Toast.LENGTH_SHORT).show();
if (!isRun) {
task.run();
}
}
public static class Task implements Runnable {
@Override
public void run() {
Log.d("TASK", "怎么就执行了Task了呢");
}
}
}
xml代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="onclickEvent"
type="com.single.androiddatabing.event.OnclickEvent" />
<variable
name="task"
type="com.single.androiddatabing.event.OnclickEvent.Task" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<Button
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{()->onclickEvent.runTask(task)}"
android:text="button1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{(view)->onclickEvent.runTask(view,task)}"
android:text="Button2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{(view)->onclickEvent.runTask(view,task,false)}"
android:text="Button3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
</android.support.constraint.ConstraintLayout>
</layout>
上面例子中三个button分别传了各自的参数,如果要指明view的话,需要在前面的括号中说明,接下来不要忘记在代码中去设置onclickEvent
、task
:
ActivityOnclick2Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_onclick2);
viewDataBinding.setOnclickEvent(new OnclickEvent());
viewDataBinding.setTask(new OnclickEvent.Task());
还有种方式也可以设置onClick,这种的话就比较单一了,其实不建议这种方式,耦合性不高:
<variable
name="buttonClick"
type="android.view.View.OnClickListener" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:onClick="@{buttonClick}"
android:text="Button4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button2" />
//activity中代码
viewDataBinding.setButtonClick(new View.OnClickListener() {
@Override
public void onClick(View v) {
//todo
}
});
集合在xml中使用:
<import type="java.util.List" />
<import type="com.single.androiddatabing.bean.User" />
<variable
name="userList"
type="List<User>" />
<variable
name="index"
type="Integer" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userList.get(0).name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userList[index].name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
不要忘了需要在代码中设置index值和userList的值:
ActivityListBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_list);
List<User> users = new ArrayList<>();
User user = new User();
user.name = "王小二";
users.add(user);
User user1 = new User();
user1.name = "王小三";
users.add(user1);
viewDataBinding.setIndex(1);
viewDataBinding.setUserList(users);
map在xml中使用
其实跟list使用差不多,直接上结果:
<import type="java.util.Map" />
<import type="com.single.androiddatabing.bean.User" />
<variable
name="userMap"
type="Map<String,User>" />
<variable
name="key"
type="String" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userMap.get(key).name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
ActivityMapBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_map);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);
include操作
这里以map
的例子来说明下如何使用,直接上代码:
<data>
<import type="java.util.Map" />
<import type="com.single.androiddatabing.bean.User" />
<variable
name="userMap"
type="Map<String,User>" />
<variable
name="key"
type="String" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userMap.get(key).name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="123" />
<include
layout="@layout/layout_include"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView3"
app:myUser='@{userMap["2"]}' />
</android.support.constraint.ConstraintLayout>
layout_include代码:
<data>
<variable
name="myUser"
type="com.single.androiddatabing.bean.User" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{myUser.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
activity中的代码:
ActivityIncludeBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_include);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);
ViewStub使用
<data>
<import type="java.util.Map" />
<import type="com.single.androiddatabing.bean.User" />
<variable
name="userMap"
type="Map<String,User>" />
<variable
name="key"
type="String" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userMap.get(key).name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="123" />
<ViewStub
android:id="@+id/view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/layout_include"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView3" />
</android.support.constraint.ConstraintLayout>
activity中代码:
ActivityViewstubBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_viewstub);
Map<String, User> users = new HashMap();
User user = new User();
user.name = "王小二";
users.put("1", user);
User user1 = new User();
user1.name = "王小三";
users.put("2", user1);
viewDataBinding.setKey("1");
viewDataBinding.setUserMap(users);
viewDataBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
LayoutIncludeBinding viewStubBinding = DataBindingUtil.bind(inflated);
User user = new User(12, "谢后");
viewStubBinding.setMyUser(user);
}
});
if (!viewDataBinding.viewStub.isInflated()) {
//viewDataBinding.viewStub获取的是ViewStubProxy
viewDataBinding.viewStub.getViewStub().inflate();
}
这里可以看出来跟include的使用基本是一样的,主要看activity中代码。这种代码记下就行,完全是机械式代码咯。
自定义属性
上面的例子中都是单一的操作view的属性,下面介绍自定义属性的玩法:
public class ViewUtils {
@BindingAdapter({"loadHighLight"})
public static void loadLight(TextView textView, String text) {
textView.setText(highlightMoney(text, text.substring(0, 2)));
}
public static SpannableStringBuilder highlightMoney(String text, String target) {
SpannableStringBuilder spannable = new SpannableStringBuilder(text);
CharacterStyle span = null;
//用他们的小写来做判断
if (!TextUtils.isEmpty(target)) {
Pattern p = Pattern.compile(target.toLowerCase());
Matcher m = p.matcher(text.toLowerCase());
while (m.find()) {
span = new ForegroundColorSpan(Color.parseColor("#FF801A"));// 需要重复!
spannable.setSpan(span, m.start(), m.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
StyleSpan styleSpan_B = new StyleSpan(Typeface.BOLD);
spannable.setSpan(styleSpan_B, m.start(), m.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return scannable;
} else {
return new SpannableStringBuilder(text);
}
}
}
上面写的自定义属性是高亮显示、加重的一个功能,所以说以后用到的地方直接调用该属性就可以了,下面看看如何使用该属性:
<data>
<import type="java.util.List" />
<import type="com.single.androiddatabing.bean.User" />
<variable
name="userList"
type="List<User>" />
<variable
name="index"
type="Integer" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:loadHighLight="@{userList.get(0).name}" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3"
app:loadHighLight="@{userList[index].name}" />
</android.support.constraint.ConstraintLayout>
看到xml里面了没,里面有app:loadHighLight
该属性的使用。activity中就没什么好说的了:
ActivityHighlightBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_highlight);
List<User> users = new ArrayList<>();
User user = new User();
user.name = "90元/月";
users.add(user);
User user1 = new User();
user1.name = "80元/月";
users.add(user1);
viewDataBinding.setIndex(1);
viewDataBinding.setUserList(users);
效果图就是如下:

双向绑定数据
上面的例子中都是数据发生变化的时候,不会主动去通知view发生变化,所以双向绑定数据能解决该问题,不用我们去关注view是不是发生了变化,下面介绍几种方式:
- Observable Objects
这种双向绑定是针对object来说的,直接让bean实体继承BaseObservable
:
public class ObservableBean extends BaseObservable {
private String firstName;
private String lastName;
public ObservableBean(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Bindable
public String getFirstName() {
return this.firstName;
}
@Bindable
public String getLastName() {
return this.lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
提供set、get方法,并且在get方法上面加上@Bindable
注解
xml如下:
<data>
<variable
name="observableBean"
type="com.single.androiddatabing.bean.ObservableBean" />
<variable
name="myClick"
type="android.view.View.OnClickListener" />
<variable
name="key"
type="String" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{observableBean.firstName}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{observableBean.lastName}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:onClick="@{myClick}"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView6" />
</android.support.constraint.ConstraintLayout>
activity中代码如下:
ActivityObservableObjectBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable_object);
final ObservableBean observableBean = new ObservableBean("张三", "李四");
viewDataBinding.setObservableBean(observableBean);
viewDataBinding.setMyClick(new View.OnClickListener() {
@Override
public void onClick(View v) {
observableBean.setFirstName("zs");
observableBean.setLastName("ls");
}
});
上面的代码可以看出来点击按钮后实体的属性发生变化了,紧接着view的属性也发生了变化。
- Observable Field
这种方式的话,是针对object的属性而言的,用到的类是ObservableField了,把刚刚的例子改动如下:
public class ObservableFieldsUser {
public ObservableField<String> firstName = new ObservableField<>();
public ObservableField<String> lastName = new ObservableField<>();
public ObservableFieldsUser(String firstName, String lastName) {
this.firstName.set(firstName);
this.lastName.set(lastName);
}
}
xml的布局基本是一样的,activity代码如下:
ActivityObservableFieldBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable_field);
final ObservableFieldsUser observableBean = new ObservableFieldsUser("张三", "李四");
viewDataBinding.setObservableFieldsUser(observableBean);
viewDataBinding.setMyClick(new View.OnClickListener() {
@Override
public void onClick(View v) {
observableBean.firstName.set("你是张三");
observableBean.lastName.set("你是李四");
}
});
系统自带的observable***还有很多,有如下类:

用法都是差不多,知道双向绑定是个怎么回事就ok了。
在RecyclerView中用Databinding重构自己的Adapter
public abstract class BaseRecyclerViewBingAdapter<T, B extends ViewDataBinding> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
protected List<T> list;
protected B dataBing;
private int variableId;
protected Context context;
public BaseRecyclerViewBingAdapter(Context context, List<T> list, int variableId) {
this.context = context;
this.list = list;
this.variableId = variableId;
}
@Override
public int getItemCount() {
return list.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//同样会根据布局生成一个相应的binding
RecyclerView.ViewHolder viewHolder;
dataBing = DataBindingUtil.inflate(
LayoutInflater.from(context), getItemLayout(viewType), null, false);
viewHolder = new BindingHolder<B>(dataBing.getRoot());
((BindingHolder) viewHolder).setBinding(dataBing);
//这里getRoot会返回布局的根view
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
T t = list.get(position);
((BindingHolder) holder).getBinding().setVariable(variableId, t);
((BindingHolder) holder).getBinding().executePendingBindings();
((BindingHolder) holder).getBinding().getRoot().setOnClickListener(v -> {
itemClick(t, position);
});
generateItem((B) ((BindingHolder) holder).getBinding(), t, position);
}
protected void generateItem(B dataBing, T t, int position) {
}
protected abstract int getItemLayout(int viewType);
protected abstract void itemClick(T item, int position);
public static class BindingHolder<B extends ViewDataBinding> extends RecyclerView.ViewHolder {
//这里在holder里面,传入一个binding对象就ok了
private B binding;
public BindingHolder(View itemView) {
super(itemView);
}
public B getBinding() {
return binding;
}
public void setBinding(B binding) {
this.binding = binding;
}
}
}
用法很简单,你只需要去继承该类,然后子类指明集合还有子类的布局就ok了。给个事例看下:
viewDataBinding.recycler.setAdapter(new BaseRecyclerViewBingAdapter<KewenItem, KewenSelectItemBinding>(this, sessions, BR.kewenItem) {
@Override
protected int getItemLayout(int viewType) {
return R.layout.kewen_select_item;
}
@Override
protected void itemClick(KewenItem item, int position) {
}
});
item的布局:
<data>
<variable
name="kewenItem"
type="com.single.androiddatabing.bean.KewenItem" />
</data>
<LinearLayout
android:layout_width="100dp"
android:layout_height="100dp">
<TextView
android:id="@+id/show_kewen"
android:layout_width="100dp"
android:layout_height="100dp"
android:gravity="center"
android:paddingLeft="@dimen/dp_10"
android:paddingRight="@dimen/dp_10"
android:textSize="@dimen/text_18"
app:zhongri="@{kewenItem}"
tools:text="大学孟子中庸学习" />
</LinearLayout>
item布局里面用到了一个app:zhongri
属性,这里是自定义属性:
@BindingAdapter({"zhongri"})
public static void loadZhongriTextColor(TextView textView, KewenItem kewenItem) {
textView.setTextColor(textView.getContext().getResources().getColor(kewenItem.textColor));
textView.setBackground(textView.getContext().getResources().getDrawable(kewenItem.drawable));
textView.setText(kewenItem.text);
}
最后效果图如下:

databinding在MvvM框架中如何使用
这里用到了google的lifecycle
框架,因为平时比较喜欢用这个框架,因此也分享给大家学习学习:
public class UserModel extends AndroidViewModel {
public ObservableField<User> userObservableField = new ObservableField<>();
private final MediatorLiveData<User> userMediatorLiveData = new MediatorLiveData<>();
public LiveData<User> getUser() {
userMediatorLiveData.setValue(new User(11, "我是UserModel中构造出来的user"));
return userMediatorLiveData;
}
public void setUserObservableField(User user) {
userObservableField.set(user);
}
public UserModel(@NonNull Application application) {
super(application);
}
/**
* A creator is used to inject the product ID into the ViewModel
* <p>
* This creator is to showcase how to inject dependencies into ViewModels. It's not
* actually necessary in this case, as the product ID can be passed in a public method.
*/
public static class Factory extends ViewModelProvider.NewInstanceFactory {
@NonNull
private final Application mApplication;
public Factory(@NonNull Application application) {
mApplication = application;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
//noinspection unchecked
return (T) new UserModel(mApplication);
}
}
}
看到了双向绑定的影子了没,上面定义了ObservableField<User>
变量,这里就是用来通知xml值发生变化了,要刷新ui了,因此可以看xml中如何搞定的:
<data>
<variable
name="userModel"
type="com.single.androiddatabing.model.UserModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.single.androiddatabing.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{userModel.userObservableField.name}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@{String.valueOf(userModel.userObservableField.age)}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>
xml中也是挺简单的,直接定义好userModel,然后获取userModel中
userObservableField
变量,最后展示bean的属性。activity中代码使用:
ActivityMvvmBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
UserModel.Factory factory = new UserModel.Factory(
getApplication());
final UserModel model = ViewModelProviders.of(this, factory)
.get(UserModel.class);
viewDataBinding.setUserModel(model);
model.getUser().observe(this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
model.setUserObservableField(user);
}
});
activity中代码也挺简单、明了的。有什么不明白的地方可以直接和我讨论,相信你会喜欢用mvvm框架的。
上面的例子代码都在这里:猛戳