DataBinding使用与分析

一.使用方式

1.单向绑定一
1)首先在module的gradle中加入以下内容:
dataBinding{
   enabled = true
}
2)新建一个实体类User,里面有两个成员变量:
public class User  {

    public ObservableField  name = new ObservableField<>();
    public ObservableField  psw = new ObservableField<>();
}
ObservableField提供了get和set方法用于读写该变量的内容。
3)新建一个布局,variable的type内容为需绑定数据实体类的全限定名,name为变量名。

    
        
    



    
        
        
    
    
        
        
    
    
4) 在Activity中加载布局并设置绑定数据:
ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);
final User user = new User();
    user.name.set("张三");
    user.psw.set("123");
    binding.setUser(user);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            user.name.set("李四");
            user.psw.set("456");
        }
    },1000);;
以上代码运行结果为:

DataBinding使用与分析_第1张图片

2.单向绑定二
实体类也可以写为以下方式,继承BaseObservable,get方法使用注解 @Bindable修饰,set方法加上notifyPropertyChanged(BR.name);
public class User extends BaseObservable {
  private String name;
    private String psw;
    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
    @Bindable
    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
        notifyPropertyChanged(BR.psw);
    }
   }
3.双向绑定
在布局文件中,将使用数据的地方由"@{user.psw}“改为”@={user.psw}",则View的数据改变时,Model的数据也随之改变。

二.说明

1.以上代码编译之后,会生成两个xml文件,其一在build/intermediates/data_binding_layout_info_type_merge/debug/mergeDebugResources/out/activity_main-layout.xml目录下,内容为:


    


    
        
        
    ...
在以上xml中,可以看到布局名称、包名、实体类及包名、view类型和标签(tag)等信息。另一个XML文件位于mvvm_demo1/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml,内容为:


    
    
...
在这个xml中,有数据绑定的view都包含了一个tag,两个xml文件的tag内容一致。
2.从DataBindingUtil.setContentView()进入,经过DataBindingUtil.bindToAddedViews->bind->DataBinderMapperImpl.getDataBinder->ActivityMainBindingImpl()来到ViewDataBinding.mapBindings方法,部分代码如下,在该方法中,根据以上xml中tag的内容把view保存在bindings[]数组中,activity较多时,该数组会占用一定内存。
if (isRoot && tag != null && tag.startsWith("layout")) {
            id = tag.lastIndexOf(95);
            if (id > 0 && isNumeric(tag, id + 1)) {
                count = parseTagInt(tag, id + 1);
                if (bindings[count] == null) {
                    bindings[count] = view;
                }

                indexInIncludes = includes == null ? -1 : count;
                isBound = true;
            } else {
                indexInIncludes = -1;
            }
        } else if (tag != null && tag.startsWith("binding_")) {
            id = parseTagInt(tag, BINDING_NUMBER_START);
            if (bindings[id] == null) {
                bindings[id] = view;
            }

            isBound = true;
            indexInIncludes = includes == null ? -1 : id;
        } 
3.在ViewDataBinding的静态代码块中有以下代码,当控件状态发生改变时,会执行OnAttachStateChangeListener(),在该监听器中有mRebindRunnable线程,每个Activity都有这样一个线程,当Activity较多时,会造成内存消耗。
ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener() {
                @TargetApi(19)
                public void onViewAttachedToWindow(View v) {
                    ViewDataBinding binding = ViewDataBinding.getBinding(v);
                    binding.mRebindRunnable.run();
                    v.removeOnAttachStateChangeListener(this);
                }

                public void onViewDetachedFromWindow(View v) {
                }
            };
4.回到ActivityMainBindingImpl构造方法,该方法中有invalidateAll()->requestRebind(),代码如下,这两处均使用handler刷新控件,handler内部使用looper执行消息循环,造成内存消耗。
if (USE_CHOREOGRAPHER) {
            mChoreographer.postFrameCallback(mFrameCallback);
        } else {
            mUIThreadHandler.post(mRebindRunnable);
        }
5.在OnAttachStateChangeListener监听器的mRebindRunnable线程中,追踪executePendingBindings->executeBindingsInternal-executeBindings,executeBindings方法部分代码如下,该代码拿到user对象,得到其属性值,最终TextViewBindingAdapter.setText()方法给view设置值,实现Model到View的数据绑定。
 androidx.databinding.ObservableField userName = null;
        androidx.databinding.ObservableField userPsw = null;
        com.example.mvvm_demo1.User user = mUser;
        java.lang.String userNameGet = null;
        java.lang.String userPswGet = null;

        if ((dirtyFlags & 0xfL) != 0) {


            if ((dirtyFlags & 0xdL) != 0) {

                    if (user != null) {
                        // read user.name
                        userName = user.name;
                    }
                    updateRegistration(0, userName);


                    if (userName != null) {
                        // read user.name.get()
                        userNameGet = userName.get();
                    }
            }
            ...
            if ((dirtyFlags & 0xdL) != 0) {
            // api target 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, userNameGet);
        }
6.在executeBindings方法中还有以下代码,在mboundView1androidTextAttrChanged对象中实现了从控件中取数据赋值给user对象的过程,完成View到Model的数据绑定。
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView1androidTextAttrChanged);

你可能感兴趣的:(Android)