【Jetpack】DataBinding(三):布局绑定类

Quibbler 2020-12-27 645

DataBinding(三):布局绑定类


        写好我们的DataBinding布局之后如何使用呢?如何初始化在<data />中定义的变量呢?



1、绑定布局

        已经将原来的XML布局转换成DataBinding支持的数据绑定布局,接下来就是将它设置给我们的Activity、Fragment等需要加载布局的地方。


1.1、Activity中绑定布局

        在使用DataBinding之前通过setContentView(int layoutResID)方法设置Activity布局:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_data_binding);
    }

        启用DataBinding后,有两种方式加载data binding layout布局:

        使用DataBinding库中的DataBindingUtil.setContentView()方法给当前Activity设置布局,返回自动生成的绑定类实例:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DataBindingLayoutBinding dataBindingBinding = DataBindingUtil.setContentView(this, R.layout.data_binding_layout);
    }

        或者先通过生成绑定类inflate()静态方法加载布局,再通过ActivitysetContentView(View view)方法设置当前Activity的布局。看似这种方法没有显示的指定layout,实际上MainLayoutBinding对应的xml不就是我们要加载的布局吗?

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MainLayoutBinding dataBindingBinding = MainLayoutBinding.inflate(getLayoutInflater());
        setContentView(dataBindingBinding.getRoot());
    }

        

1.2、Fragment中绑定布局

        在自定义FragmentonCreateView()中一般通过DataBindingUtilinflate()方法绑定布局:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        FragmentBlankBinding fragmentBlankBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_blank, container, false);
        ... ...
        return fragmentBlankBinding.getRoot();
    }


1.3、RecyclerView绑定布局

        在RecyclerView等组件中通过DataBindingUtil.inflate()方法加载布局:

    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        RecyclerViewItemBinding recyclerViewItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
                R.layout.recycler_view_item, parent, false);
        //设置DataBinding值
        ... ...
        return new ViewHolder(recyclerViewItemBinding);
    }


1.4、未知类型的绑定

        实际项目中List、RecyclerView很复杂,加载的布局在加载前可能是未知的,无法预知加载哪个布局,或者可以加载多种类型的布局。这时候可以先加载xml布局,在将其设置给ViewDataBinding通用的抽象类型变量:

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //LayoutInflater从xml数据绑定布局加载View
        View view = inflater.inflate(R.layout.fragment_blank, container, false);
        //将View设置给ViewDataBinding
        ViewDataBinding fragmentBlankBinding = DataBindingUtil.bind(view);
        //...
        return view;
    }

        


2、绑定类 extends ViewDataBinding

        DataBinding根据data binding layout布局为我们自动生成对应的Binding类,在项目的build/generated/data_binding_base_class_source_out/debug/out/包名/databinding目录下。继承自ViewDataBinding抽象类,实现ViewBinding接口:

    /** A type which binds the views in a layout XML to fields. */
    public interface ViewBinding {
        /**
         * Returns the outermost {@link View} in the associated layout file. If this binding is for a
         * {@code <merge>} layout, this will return the first view inside of the merge tag.
         */
        @NonNull
        View getRoot();
    }


2.1、ViewDataBinding抽象类

        ViewDataBinding抽象类是所有自动生成的绑定类的父类,实现了ViewBinding接口,并且提供一些通用的方法。

    public abstract class ViewDataBinding extends BaseObservable implements ViewBinding {
        /**
         * The root View that this Binding is associated with.
         */
        private final View mRoot;
        
        @Override
        public View getRoot() {
            return mRoot;
        }
        public abstract boolean setVariable(int variableId, @Nullable Object value);
        ...
    }


2.2、绑定类名称规则

        类名称基于布局文件的名称:首字母大写的驼峰命名法并在末尾添加Binding后缀。比如布局文件名为 data_binding_layout.xml,因此生成的对应类为 DataBindingLayoutBinding,包含从布局属性到布局视图的所有绑定变量,并且知道如何为绑定表达式指定值。

        还可以在<data />中用class指定生成的绑定类名:

    <data class="MainLayoutBinding">
        ...
    </data>


2.3、获取控件

        布局中原来是通过findViewById获取其中的控件。现在在DataBinding布局中定义控件,要获取的控件必须要有id,否则无法获取到:

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{name}" />

         直接通过DataBinding布局对象就可以拿到其中的控件对象,无需再通过findViewById。对象名是id去除下划线的驼峰命名法:

    TextView textView = dataBindingBinding.textView;

        getRoot()方法是通用的方法,可以获取根布局View对象。


2.4、变量setter/getter

        在布局中定义了属性如何初始化设置值呢?数据绑定库为布局中声明的每个变量生成访问器方法。比如在布局中定义了String类型的变量name:

    <variable
        name="name"
        type="String" />

        在自动生成的DataBinding对象中就会有对应的setter和getter方法:

    //设置
    dataBindingBinding.setName("");
    //获取
    dataBindingBinding.getName();


2.5、BR类

        数据绑定库在模块包中生成一个名为BR的类,在项目的build/generated/ap_generated_sources/debug/out/androidx/databinding/library/baseAdapters/BR.java目录下,其中包含用于数据绑定的资源的 ID。

        通过该BR中的ID,调用父类ViewDataBindingsetVariable(int variableId,Object value)方法同样可以设置指定ID资源的值:

    dataBindingBinding.setVariable(BR.name, "Quibbler");

        这种方法特别有用,尤其是对于变量无法预先知道的data binding layout。



3、其它

        使用ViewDataBinding有一些注意点,以后遇到其它问题会继续补充,记录经验。


3.1、线程安全

        以前我们知道在开发Android的时候,子线程中设置View数据是不安全的。但是ViewDataBinding以在后台线程中更改数据模型(这个模型不能是集合)。数据绑定会在求值过程中对每个变量/字段进行本地化,以避免出现并发问题。



参考资料:

        Jetpack > Libraries > Databinding

        Data Binding:Generated binding classes

        

不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com