Jetpack DataBinding使用了大量的注解处理器和代码生成技术,将XML文件中的View和ViewGroup与数据对象关联起来,从而实现数据和UI视图之间的直接联系。接下来,我们可以从以下几个方面对Jetpack DataBinding源码进行走读:
- 注解处理器
Jetpack DataBinding使用了注解处理器来在编译时生成与每个XML文件相对应的Binding类。这些Binding类包含了用来访问View和ViewGroup的getter和setter方法,以及用来更新UI的方法。注解处理器源码位于DataBinding库的compiler模块中,其中核心的类是DataBinderMapper.java
、DataBindingProcessor.java
和DataBindingProcessorIncremental.java
等。
DataBinderMapper.java类是DataBinding组件中的一个重要类。在编译时,DataBinding会扫描工程中所有的XML文件,用DataBinderMapper作为数据绑定器与每个XML文件生成对应的Binding类。DataBindingProcessor类则是一个基于AnnotationProcessor的抽象框架,所有的DataBinding注解处理器都必须继承自该类。而DataBindingProcessorIncremental类则用于增量式编译,用于优化DataBinding的编译速度。
- DataBinding机制的运行原理
DataBinding机制的运行原理是通过LayoutInflater.Factory2接口实现的。该接口有两个方法onCreateView
和onCreateView
。其中onCreateView返回值是一个View,而onCreateView2返回值是一个DataBinding,在绝大多数情况下,DataBinding会使用onCreateView2方法来生成与XML对应的Binding。
在生成DataBinding时,系统会使用DataBinderMapper类中已经缓存的数据绑定器来查找XML对应的Binding类,如果能够找到对应的Binding类,则使用对应的Binding类生成DataBinding对象,并将DataBinding对象保存在缓存中。否则,系统将根据XML文件中的布局规则和数据模型规则,在编译时动态生成对应的DataBinding类,然后再通过生成的DataBinding类创建DataBinding对象。
- 数据绑定关键类: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方法。
- 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方法实现的。
- 常用的绑定表达式:
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方法)。
- 双向数据绑定
双向数据绑定是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的优缺点,以及它适用的场景。