Databinding使用、Databinding原理、Androidx集成Databinding、Databinding源码分析、Databinding双向绑定原理

Dolly ·
更新时间:2024-09-21
· 951 次阅读

简介

Databinding是谷歌的一个官方支持库,它允许您使用声明性格式而不是通过编程方式将布局中的UI组件绑定到应用程序中的数据源。
通常在活动中使用调用UI框架方法的代码来定义布局。例如,调用findViewById()以查找TextView窗口小部件并将其绑定到变量。
因为它通过在布局文件中绑定组件,您可以删除活动中的许多UI框架调用,从而使它们更易于维护。这也可以提高应用程序的性能,并有助于防止内存泄漏和空指针异常

Androidx集成Databinding

1、将dataBinding元素添加到 build.gradle应用程序模块中

android { ...... dataBinding { enabled = true } }

2、gradle编译会根据dataBinding设置自动引包,无需个人添加implementation等。因此,需要在项目中配置Androidx环境。
文件位置:项目根目录gradle.properties

android.useAndroidX=true android.enableJetifier=true Databinding使用

Databinding的改动主要涉及两个模块,一个模块为布局文件layout,另一个模块为数据提供方(Activity,Fragment,或者viewmodel,这里我们以Activity为例子)。
一、 layout模块变动,布局文件的最外层需要套一层layout标签。

// 利用TextView测试单向数据绑定 // 利用CheckBox测试双向数据绑定

二、layout布局文件的data标签绑定了类数据ProductInfo

public class ProductInfo { public String name; public boolean isLate; public ProductInfo(String name, boolean isLate) { this.name = name; this.isLate = isLate; } }

三、数据提供方Activity代码
layout布局文件写完执行build->rebuild project会自动生成DataBindingActivityBinding对象

public class DataBindingActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); DataBindingActivityBinding bindingActivityBinding = DataBindingUtil.setContentView(this, R.layout.data_binding_activity); bindingActivityBinding.setProductInfo(new ProductInfo("小米公交卡", true); } }

如上,一个比较简单的Databinding使用,Databinding使用还包含自定义view、绑定表达式等,这里不着重讲了,可以参考如下文档:
绑定表达式:
https://developer.android.google.cn/topic/libraries/data-binding/expressions
通过BindingAdapters自定义view:
https://developer.android.google.cn/topic/libraries/data-binding/binding-adapters

概念以及APT自动生成的文件

一、概念讲解
首先陈述几个Databinding相关的概念
1、Java中的APT的工作过程
APT即Annotatino Processing Tool, 他的作用是处理代码中的注解, 用来生成代码, 换句话说, 这是用代码生成代码的工具。
2、双向绑定
数据变更可以通知到控件,控件的状态变更(例如checkbox的开关)会同步到绑定的数据对象。
3、Databinding跟mvvm模式的关系
Databinding本质跟mvvm并没有关系,它的出现因为屏蔽了findviewbyid,所以有助于防止内存泄漏和空指针异常。属于view层的优化。
4、使用双向数据绑定的无限循环
使用双向数据绑定时,请注意不要引入无限循环。当用户更改属性时,使用注释的方法将 @InverseBindingAdapter被调用,并将该值分配给属性。反过来,这将调用使用注释的方法 @BindingAdapter,这将触发对使用注释的方法的另一次调用@InverseBindingAdapter,依此类推。
因此,在使用注释的方法中,通过比较新值和旧值来打破可能的无限循环非常重要。
这里列一个防止无限循环的例子:

public class CompoundButtonBindingAdapter { @BindingAdapter("android:checked") public static void setChecked(CompoundButton view, boolean checked) { // 这里通过比较新值和旧值来打破可能的无限循环 if (view.isChecked() != checked) { view.setChecked(checked); } } }

二、APT技术自动生成的文件
1、layout转换的文件
文件位置build/intermediates/下

2、生成的Binding管理类
DataBindingActivityBindingImpl类,用户向布局文件下发数据,ui展示。

2、看下InverseBindingListener

public interface InverseBindingListener { /** * Notifies the data binding system that the attribute value has changed. */ void onChange(); }

反向数据绑定是一个接口
3、看下他的实现类,代码在DataBindingActivityBindingImpl

// Inverse Binding Event Handlers private androidx.databinding.InverseBindingListener mboundView2androidCheckedAttrChanged = new androidx.databinding.InverseBindingListener() { @Override public void onChange() { // Inverse of productInfo.isLate // is productInfo.isLate = (boolean) callbackArg_0 boolean callbackArg_0 = mboundView2.isChecked(); // localize variables for thread safety // productInfo.isLate boolean productInfoIsLate = false; // productInfo com.archie.mvvm.entity.ProductInfo productInfo = mProductInfo; // productInfo != null boolean productInfoJavaLangObjectNull = false; productInfoJavaLangObjectNull = (productInfo) != (null); if (productInfoJavaLangObjectNull) { productInfo.isLate = ((boolean) (callbackArg_0)); } } };

这里可以看到onChange内部其实是对Product对象的赋值。这里大概就能体现出Java的神奇,因为Product是个对象,所以传递的是对象的引用,这里通过对象的引用变更了对象的属性,那么内存中的这个对象本质数据已经变更。
4、接下来看下怎么回调的onChange(),其实还DataBindingActivityBindingImpl.executeBindings()

protected void executeBindings() { ...... // batch finished if ((dirtyFlags & 0x18L) != 0) { // api target 1 androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, productInfoName); androidx.databinding.adapters.CompoundButtonBindingAdapter.setChecked(this.mboundView2, productInfoIsLate); androidx.databinding.adapters.CompoundButtonBindingAdapter .setListeners(this.mboundView2 , (android.widget.CompoundButton.OnCheckedChangeListener)productInfoOnClickBoxAndroidWidgetCompoundButtonOnCheckedChangeListener , mboundView2androidCheckedAttrChanged); } }

这里可以看到androidx.databinding.adapters.CompoundButtonBindingAdapter.setListeners()设置了反向数据监听。
5、看下CompoundButtonBindingAdapter

public class CompoundButtonBindingAdapter { @BindingAdapter("android:checked") public static void setChecked(CompoundButton view, boolean checked) { if (view.isChecked() != checked) { view.setChecked(checked); } } @BindingAdapter(value = {"android:onCheckedChanged", "android:checkedAttrChanged"}, requireAll = false) public static void setListeners(CompoundButton view, final OnCheckedChangeListener listener, final InverseBindingListener attrChange) { if (attrChange == null) { view.setOnCheckedChangeListener(listener); } else { view.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (listener != null) { listener.onCheckedChanged(buttonView, isChecked); } attrChange.onChange(); } }); } } }

这里很清晰了,setListeners监听了button的点击事件,最终回传到了InverseBindingListener.onChange()。然后实现类会在onChange中对对象赋值,从而做到了反向数据绑定。

总结

一个新技术的使用,必然会有很多争论点,这里说下Databinding的优缺点
优点:
1、彻底去掉了findviewbyid,并有助于防止内存泄漏和空指针异常。
2、将View层代码抽象为了数据状态,极大减少了数据层和view层的代码耦合,同时也能减少model和view的回调处理。
3、 易于维护和测试
缺点:
1、通过源码我们可以看到,维护了view数组,造成内存占用。
2、使用了handler和looper循环。
3、apt技术会生成类文件,占用内存。
任何一个技术都有优缺点,在面向对象思维的背景下,减少逻辑调用显得格外重要。作为谷歌官方的架构组件,在历史的长河中必定证明了优点大于缺点。所以,盘它。


作者:archie_7



databinding

需要 登录 后方可回复, 如果你还没有账号请 注册新账号