使用
1.在app的build.gradle文件下做如下配置
android {
......
dataBinding {
enabled = true
}
}
2.在布局文件中配置
3.在Activity中调用方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBindingImpl binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
}
4.编译之后生成的布局文件中添加了tag
/Users/renzhenming/AndroidStudioProjects/RetrofitDemo/app/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
注意,这个tag很有用,源码中通过tag来遍历布局
原理
public class User extends BaseObservable {
private String name;
private String pwd;
}
ActivityMainBinding binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
user=new User("a","123");
binding.setUser(user);
setContentView
在Activity中使用的时候,先绑定布局文件,那么这个操作都做了什么?我们从源码中找答案
ActivityMainBinding binding= DataBindingUtil.setContentView(this,R.layout.activity_main)
在这个方法中,注意contentView是系统布局DecorView中的content节点,layoutId是当前Activity的布局id
public static T setContentView(@NonNull Activity activity,
int layoutId, @Nullable DataBindingComponent bindingComponent) {
activity.setContentView(layoutId);
View decorView = activity.getWindow().getDecorView();
ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}
这里childrenAdded正常情况下必须是1,因为parent是系统的content节点,而使用databing,我们自己写的布局的根结点需要是一个
private static T bindToAddedViews(DataBindingComponent component,
ViewGroup parent, int startChildren, int layoutId) {
final int endChildren = parent.getChildCount();
final int childrenAdded = endChildren - startChildren;
if (childrenAdded == 1) {
final View childView = parent.getChildAt(endChildren - 1);
return bind(component, childView, layoutId);
} else {
final View[] children = new View[childrenAdded];
for (int i = 0; i < childrenAdded; i++) {
children[i] = parent.getChildAt(i + startChildren);
}
return bind(component, children, layoutId);
}
}
继续往下就进入到了com.项目路径.DataBinderMapperImpl类中,在getDataBinder中可以看到,返回了ActivityMainBindingImpl
@Override
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
if(localizedLayoutId > 0) {
final Object tag = view.getTag();
if(tag == null) {
throw new RuntimeException("view must have a tag");
}
switch(localizedLayoutId) {
case LAYOUT_ACTIVITYMAIN: {
if ("layout/activity_main_0".equals(tag)) {
return new ActivityMainBindingImpl(component, view);
}
throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
}
}
}
return null;
}
而在构造ActivityMainBindingImpl的时候可以看出,在mapBindings方法中,将布局中的子节点保存在了数组中,于是通过binding对象就可以取到这些节点了如:binding.tv1
public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
}
setUser()
进入ActivityMainBindingImpl中
public void setUser(@Nullable com.example.databindingdemo_20210117.User User) {
//1.给User设置一个监听器(OnPropertyChangedCallback)监听数据的变化,当数据变化时,回调onPropertyChanged()方法
updateRegistration(0, User);
this.mUser = User;
synchronized(this) {
mDirtyFlags |= 0x1L;
}
notifyPropertyChanged(BR.user);
super.requestRebind();
}