Databinding使用记录

###使用记录和注意项

  1. Databinding的插件对AS的支持还是有些缺陷,有时候ViewDataBinding读取不到variable的setter,
    build->generated->source->apt->debug-><包名>->databinding目录下查找对应方法。如果存在,那可能只是AS的误报。
  2. @BindingAdapter注解需要修饰静态(static)方法,不需要设置到viewdatabinding中,apt会自动查找并转换。具体实现可以在对应的viewDataBinding类的executeBindings方法中找到。
  3. 在xml的使用相关的工具类或者方法,需要在<data>中引用对应的类(包括R文件)。eg:<import type="android.view.View"/>
  4. 隐式属性引用

    <CheckBox
      android:id="@+id/cb_Test"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="选中"
      />
    <TextView
      android:layout_width="match_parent"
      android:layout_height="100dp"
      android:text="选中显示"
      android:gravity="center"
      android:visibility="@{cbTest.checked?View.VISIBLE:View.GONE}"
      />
    

    CheckBox的id是cb_Test,而引用的变量时cbTest,变量名称使用是根据ViewDatabinding的属性名称,而非XML中的ID.

5.反向绑定

  1. @InverseBindingMethod
    public @interface InverseBindingMethod {

        /**
         * The View type that is associated with the attribute.
         */
        Class type();

        /**
         * The attribute that supports two-way binding.
         */
        String attribute();

        /**
         * The event used to notify the data binding system that the attribute value has changed.
         * Defaults to attribute() + "AttrChanged"
         */
        String event() default "";

        /**
         * The getter method to retrieve the attribute value from the View. The default is
         * the bean method name based on the attribute name.
         */
        String method() default "";
    }

- event()和method()如果为空,都会默认采用attribute的标准命名格式
- event:attribute() + "AttrChanged"          :触发数据更新的事件
- method:get+attribute() 或者 is+attribute() :获取数据值的方法

定义反向绑定完成后,需要设置触发反向绑定的方法,通常采用@BindingAdapter(value = {event()的值}, requireAll = false)注册一个参数变化监听方法。

例如TextView的文本修改监听:

    @BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
            "android:afterTextChanged", "android:textAttrChanged"}, requireAll = false)
    public static void setTextWatcher(TextView view, final BeforeTextChanged before,
            final OnTextChanged on, final AfterTextChanged after,
            final InverseBindingListener textAttrChanged) {
        final TextWatcher newValue;
        if (before == null && after == null && on == null && textAttrChanged == null) {
            newValue = null;
        } else {
            newValue = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    if (before != null) {
                        before.beforeTextChanged(s, start, count, after);
                    }
                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (on != null) {
                        on.onTextChanged(s, start, before, count);
                    }
                    if (textAttrChanged != null) {      //这里是重点
                        textAttrChanged.onChange();
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {
                    if (after != null) {
                        after.afterTextChanged(s);
                    }
                }
            };
        }
        final TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
        if (oldValue != null) {
            view.removeTextChangedListener(oldValue);
        }
        if (newValue != null) {
            view.addTextChangedListener(newValue);
        }
    }
这个方法监听4个xml属性:

1. android:beforeTextChanged 
2. android:onTextChanged
3. android:afterTextChanged
4. android:textAttrChanged 

反向绑定主要需要android:textAttrChanged即InverseBindingListener监听器。该监听器会在当前的ViewDataBinding类中自动添加,作为反向刷新的回调。

**用通俗点的话说,我们需要在EditText的录入事件里面修改数据源的值,那么我们就需要在EditText的输入事件里添加数据源刷新回调。**
至于其他三个属性对应着监听器**TextWatcher**的三个方法,可以在xml里面赋值,否则传null

额外补充点:

1)其他三个属性的赋值例子代码:    

        xml:
        <EditText
            android:id="@+id/etText"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@={viewHolder.mEditTest}"
            android:onTextChanged="@{viewHolder.changed}"  
            android:gravity="center"
            />

        viewHolder类中:
        public TextViewBindingAdapter.OnTextChanged changed = new TextViewBindingAdapter.OnTextChanged() {
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    Log.e("url","changed");
                }
            };


2)该setTextWatcher事件在executeBindings()中已经完成,不会覆盖activity中的TextWatcher事件
  1. @InverseBindingAdapter(用于重新实现UI返回值给数据源的getter方法,实现这个就不需要@InverseBindingMethod了)

    @InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
    public static String getTextString(TextView view) {
        return view.getText().toString();
    }
    
    • attribute:对应双向绑定的属性,eg: android:text或者app:refresh
    • event:触发数据更新的事件,与上面的@BindingAdapter关联(关联点:android:textAttrChanged)

END

–Nowy

–2018.10.22

分享到