jetpack中Databinding的源码走读

53 阅读6分钟

Jetpack DataBinding使用了大量的注解处理器和代码生成技术,将XML文件中的View和ViewGroup与数据对象关联起来,从而实现数据和UI视图之间的直接联系。接下来,我们可以从以下几个方面对Jetpack DataBinding源码进行走读:

  1. 注解处理器

Jetpack DataBinding使用了注解处理器来在编译时生成与每个XML文件相对应的Binding类。这些Binding类包含了用来访问View和ViewGroup的getter和setter方法,以及用来更新UI的方法。注解处理器源码位于DataBinding库的compiler模块中,其中核心的类是DataBinderMapper.javaDataBindingProcessor.javaDataBindingProcessorIncremental.java等。

DataBinderMapper.java类是DataBinding组件中的一个重要类。在编译时,DataBinding会扫描工程中所有的XML文件,用DataBinderMapper作为数据绑定器与每个XML文件生成对应的Binding类。DataBindingProcessor类则是一个基于AnnotationProcessor的抽象框架,所有的DataBinding注解处理器都必须继承自该类。而DataBindingProcessorIncremental类则用于增量式编译,用于优化DataBinding的编译速度。

  1. DataBinding机制的运行原理

DataBinding机制的运行原理是通过LayoutInflater.Factory2接口实现的。该接口有两个方法onCreateViewonCreateView。其中onCreateView返回值是一个View,而onCreateView2返回值是一个DataBinding,在绝大多数情况下,DataBinding会使用onCreateView2方法来生成与XML对应的Binding。

在生成DataBinding时,系统会使用DataBinderMapper类中已经缓存的数据绑定器来查找XML对应的Binding类,如果能够找到对应的Binding类,则使用对应的Binding类生成DataBinding对象,并将DataBinding对象保存在缓存中。否则,系统将根据XML文件中的布局规则和数据模型规则,在编译时动态生成对应的DataBinding类,然后再通过生成的DataBinding类创建DataBinding对象。

  1. 数据绑定关键类:ViewDataBinding

ViewDataBinding是DataBinding的一个关键类,实现了与View和数据模型之间的绑定。它是所有DataBinding类的基类,在其内部实现了binding组件和数据对象之间的绑定关系。ViewDataBinding中包含的成员包括一个View对象和一个数据对象,同时还有一些用于在XML和Java代码中绑定View对象和数据对象的方法。例如:setVariable(int value, Object variable)方法、executePendingBindings()方法或unbind()方法等等。

ViewDataBinding中的inflate方法用于将XML布局文件转换为真实的View对象,并返回一个DataBinding对象。该方法会在编译时自动生成的Binding类中调用,以及在运行时动态生成的DataBinding类中调用。 在编译时自动生成的Binding类中,inflate方法会接收一个LayoutInflater对象和ViewGroup对象作为参数,然后返回一个DataBinding对象。在运行时动态生成的DataBinding类中,由于没有LayoutInflater对象和ViewGroup对象的实例,因此可以使用BindViewBinding.inflateInflater()方法来获取插入到已存在的layout中的LayoutInflater对象,以及将已存在的layout装载到ViewGroup中的inflate方法。

  1. DataBinding的观察者机制

可以通过在XML中使用观察者模式来跟踪数据变化,以更新UI界面。DataBinding库中的观察者模式机制是基于LiveData实现的。LiveData是一个可观察的数据容器,在数据发生变化时会通知所有注册的观察者对象。当数据源的数据发生变化时,LiveData会自动更新UI视图,以反映新的数据状态。

为了使观察者模式能够正常工作,必须使用具有适当作用域限制和生命周期感知的LiveData观察者对象。Jetpack DataBinding提供了LiveDataBindingUtil类,用来绑定LiveData与ViewDataBinding的数据绑定关系。

LiveDataBindingUtil类中的bind方法返回一个LifecycleOwner对象和LiveData对象,用于将LiveData的数据变化通知到ViewDataBinding中。其中LifecycleOwner对象表示子组件的生命周期,LiveData会跟踪LifecycleOwner对象的生命周期,以便在活动(Activity)或片段(Fragment)被销毁时及时停止LiveData的观察者。LiveData的观察者的注册和取消方法是使用LiveData对象的observe方法和removeObserve方法实现的,而LiveData的数据更新则是通过LiveData对象的setValue或postValue方法实现的。

  1. 常用的绑定表达式:

DataBinding库中最重要的特性之一是绑定表达式(Binding Expression),也称为数据绑定表达式。绑定表达式能够在XML文件中的特定区域中代表某些Java代码,因此可以轻松地绑定数据和UI。以下是一些常用的绑定表达式:

@{data.name}:访问名为data的数据对象的name属性。

@{view.visibility == View.GONE ? View.VISIBLE : View.GONE}:根据View的可见性状态来改变View的可见性。

@{viewModel.onClick(view)}:当单击View时,调用ViewModel对象的onClick方法。

@{handler.onClick}:当单击View时,调用Handler对象的onClick方法。

@{map.get(key)}:根据给定的key获取Map对象的值。

上述绑定表达式中的data、view、viewModel等变量都是在布局文件所绑定的数据对象中定义的变量名,在变量名后面跟随属性访问器(getter方法)。

  1. 双向数据绑定

双向数据绑定是DataBinding的一个重要特性之一,它可以使视图和模型之间的数据状态同步。一般来说,双向数据绑定是使用@{}语法中的()符号表示的。例如:

<EditText
    android:text="@={model.name}" />

上述代码表示将EditText的文本内容与数据模型中的name属性绑定,并且可以支持该属性的改变,即文本内容的修改也会同步到数据对象中。DataBinding库还为简单类型和自定义类型定义了适当的转换器,以确保数据类型的正确性。例如:

@InverseMethod("convertStringToInt")
public static String convertIntToString(int value) {
    return String.valueOf(value);
}
 
public static int convertStringToInt(String value) {
    try {
        return Integer.parseInt(value);
    } catch (NumberFormatException e) {
        return 0;
    }
}

以上代码定义了一个双向数据绑定函数,并使用@InverseMethod注解将该函数与相应的转换器关联起来。该函数使用String类型的value参数做为输入,将其转换成int类型的返回结果。而另一个函数使用int类型的value参数作为输入,然后将其转换成String类型的返回结果。

综上所述,Jetpack DataBinding是一个非常强大和灵活的库,它支持视图与模型之间的数据绑定和双向数据绑定,可以使应用程序更容易实现MVC或MVVM体系结构。对于开发人员来说,深入理解Jetpack DataBinding的源代码和实现原理,将有助于更高效地使用该库,并且更好地了解Jetpack DataBinding的优缺点,以及它适用的场景。