一、基本的使用姿势
1. module的build.gradle文件加上一行配置代码
android {
... dataBinding {
enabled = true
}}
2. 创建布局文件
只需要在之前布局的基础上,外层嵌套 即可。
name="student"
type="com.xiaweizi.bean.Student"/>
name="student"
type="Student"/>
-->
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
因为XML是不支持自定义导包的,所以通过import先导包,如果类名相同的话可以通过alias进行区分:
alias="MyView"/>
name="view1"
type="View"/>
name="view2"
type="MyView"/>
这个时候会在app\build\generated\source\debug\包名路径下生成对应的binding类,命名方式,举个例子最为直接:
原XML名:activity_main ----> 生成对应的binding名: ActivityMainBinding
3. Activity中替换原来的setContentView()代码
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
二、事件的binding
1.单向binding
案例1:(view id)
android:id="@+id/tv_content"
android:text="@{student.name}"
android:layout_width="match_parent"
android:layout_height="50dp"/>
在代码中通过binding直接可以获取到这个TextView
mBinding.tvContent
案例2:(click event)
①定义按键处理的类型
public class Presenter {
//Android标准的事件类型,需要注意Method中的参数和api中的保持一致
public void onTextChanged(CharSequence s, int start, int before, int count) {
employee.setFirstName(s.toString());
employee.setFired(!employee.isFired.get());
//binding.setEmployee(employee);
}
//自定义的事件类型
public void onClickListenerBinding(Employee employee) {
Toast.makeText(SimpleActivity.this, employee.getLastName(),
Toast.LENGTH_SHORT).show();
}
}
②、在xml中声明制定的案件处理的类型和指定事件
name="presenter"
type="com.github.markzhai.sample.SimpleActivity.Presenter"/>
//Android标准的事件类型
android:id="@+id/et_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入 First Name jiaoyin"
android:onTextChanged="@{presenter::onTextChanged}"/>
//自定义的事件类型
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:onClick="@{() -> presenter.onClickListenerBinding(employee)}"
android:text="@{employee.lastName}"/>
2.双向binding
之前说的单向绑定,即当数据变化,通过mBinding.setStudent(student)方式驱动UI的改变
而双向绑定,无论View还是ViewModel谁改变,都会驱动另一方的改变,实现双向绑定有两种方式:继承BaseObservable或者使用ObservableField创建成员变量。
案例1:继承BaseObservable:
public class Employee extends BaseObservable {
private String mLastName;
private String mFirstName;
public Employee(String lastName, String firstName) {
mLastName = lastName;
mFirstName = firstName;
isFired.set(false);
}
@Bindable
public String getLastName() {
return mLastName;
}
public void setLastName(String lastName) {
mLastName = lastName;
notifyPropertyChanged(com.github.markzhai.sample.BR.lastName);
//notifyChange();
}
}
这个时候当调用setLastName()方法,不仅数据改变,UI中的TextView内容也会随之改变。
我们可以发现有两个方法:notifyPropertyChanged()和notifyChange,一个是更新指定的变量,第二个是更新所有该ViewModel中的对象。
而notifyPropertyChanged(int fieldId)里面传的参数,即上面通过@Bindable注解创建对应的变量id。
案例2:使用ObservableField创建成员变量
public class Employee extends BaseObservable {
private String mLastName;
private String mFirstName;
public ObservableArrayMap user = new ObservableArrayMap<>();
private String mAvatar;
public ObservableBoolean isFired = new ObservableBoolean();
public Employee(String lastName, String firstName) {
mLastName = lastName;
mFirstName = firstName;
isFired.set(false);
}
public void setFired(boolean fired) {
isFired.set(fired);
}
@Bindable
public String getAvatar() {
return mAvatar;
}
public void setAvatar(String avatar) {
mAvatar = avatar;
}
}
通过使用ObservableField创建的对象作用相当于第一种的方案,支持ObservableInt、ObservableBoolean或者是ObservableField指定的类型、ObservableArrayMap、ObservableArrayList等。
ObservableField内部已经封装了get和set方法,如果成员变量是public属性,直接通过
mStudent.name.set("shabi");
String name = mStudent.name.get();
设置和获取对应的成员变量的值。
其他用法:
2. ViewStub和include
dataBinding同样是支持ViewStub的,使用起来也很简单,直接贴代码了。
android:id="@+id/view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/viewstub"/>
代码中:
View inflate = binding.viewStub.getViewStub().inflate();
inflate即为替代ViewStub的View.
至于include更简单,用法跟以前是差不多,唯一不同的是可以将ViewModel传到下一个XML中:
bind:student="@{student}"/>
layout_include中同样可以共享student这个对象。
3. @BindingConversion
dataBinding还支持对数据的转换,或者是类型的转换
4.自定义的属性之BindingAdapter的使用
案例:
//1、xml定义
android:id="@+id/username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="35sp"
android:text="@{user.name}"/>
//2、BindingAdapter自定义
public class TextViewBindingAdapter {
@BindingAdapter("android:text")
public static voidsetText(TextView view, CharSequence text) {
final CharSequence oldText = view.getText();
if (text == oldText || (text == null && oldText.length() == 0)) {
return;
}
if (text instanceof Spanned) {
if (text.equals(oldText)) {
return; // No change in the spans, so don't set anything.
}
} else if (!haveContentsChanged(text, oldText)) {
return; // No content changes, so don't set anything.
}
view.setText(text);
}
}
//3、更新User的name的值
User user = new User(name, age);
mBinding.setUser(user);
databinding框架,会做如下几件事情:
①计算出@{user.name} 表达式的值;
②寻找合适的BindingAdapter,如果找到,就调用它对应BindingAdapter里面的(setText)方法;
③如果没有找到合适的BindingAdapter,就在View上寻找合适的(setText)方法调用;
如此类推,可以自定义BindingAdapter..............
5. DataBindingComponent
通过BindingAdapter是可以增加一些自定义的属性或者是修改Android原生的属性,但是它有一个弊端,就是全局修改所有的相关属性,不过配合上DataBindingComponent就可以解决这个问题。
6.RecyclerView中的应用
案例:
//xml定义部分:
xmlns:android="http://schemas.android.com/apk/res/android">
name="presenter"
type="com.github.markzhai.sample.ListActivity.Presenter"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
//初始化 recycleview 和 adapter部分
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_list);
mBinding.setPresenter(new Presenter());
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mEmployeeAdapter = newEmployeeAdapter(this);
mBinding.recyclerView.setAdapter(mEmployeeAdapter);
List demoList = new ArrayList<>();
demoList.add(new Employee("Zhai", "Mark", false));
demoList.add(new Employee("Zhai2", "Mark2", false));
demoList.add(new Employee("Zhai3", "Mark3", true));
demoList.add(new Employee("Zhai4", "Mark4", false));
mEmployeeAdapter.addAll(demoList);
}
//自定义viewholder部分
public class BindingViewHolder
extends RecyclerView.ViewHolder {
private T mBinding;
public BindingViewHolder(T binding) {
//注意,这里是要设置 binding的rootview 给到viewholder中
super(binding.getRoot());
mBinding = binding;
}
public T getBinding() {
return mBinding;
}
}
//自定义adapter部分
public class EmployeeAdapter extends RecyclerView.Adapter {
@Override
public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewDataBinding binding;
if (viewType == ITEM_VIEW_TYPE_ON) {
//加载出 DataBinding的对象
binding =DataBindingUtil.inflate(mLayoutInflater,
R.layout.item_employee, parent, false);
} else {
binding =DataBindingUtil.inflate(mLayoutInflater,
R.layout.item_employee_off, parent, false);
}
//注意
returnnew BindingViewHolder(binding);
}
@Override
public void onBindViewHolder(BindingViewHolder holder, int position) {
final Employee employee = mEmployeeList.get(position);
//注意:
//设置 variable变量,并内部有去做 notifyDataChange的动作
holder.getBinding().setVariable(com.github.markzhai.sample.BR.item, employee);
//execute,以便马上更新
holder.getBinding().executePendingBindings();
}