概述 (Summary)
最近在项目中,遇到一个关于使用ViewBinding的问题
在使用<include />标签且layout的文件来自aar中的文件时,
生成的ViewBinding中映射layout的类型是View
,而不是我们期望的XxxBinding
,
但是如果layout文件来自同一个工程中的另一个module,则会生成XxxBinding
类型。
问题 (Issue)
layout文件:
<!-- activity_awesome.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
<include android:id="@+id/includes" layout="@layout/included_buttons" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- included_buttons.xml 在aar中-->
<androidx.constraintlayout.widget.ConstraintLayout>
<Button android:id="@+id/include_me" />
</androidx.constraintlayout.widget.ConstraintLayout>
生成的Binding文件
public final class ActivityAwesomeBinding implements ViewBinding {
@NonNull
public final View includes;
}
分析 (Analysis)
-
对比正常生成和非正常生成时, gradle tasks的执行情况
当layout文件在同工程的另一个module中,能够正常生成
XxxBinding
类型时,会多执行该module的相关tasks:
dataBindingMergeDependencyArtifactsDebug
dataBindingMergeGenClassesDebug
dataBindingGenBaseClassesDebug -
分析Android Gradle Plugin源码
android.databinding.tool.writer.ViewBinderKt#toViewBinder 该方法直接忽略了aar中layout对应的XxxBinding
// Check to make sure that the ID matches a binding. Ignored tags like <merge> or <fragment>
// might have an ID but not have an actual binding. Only use ID if a match was found.
val rootBinding = bindings.singleOrNull { it.id == id }
if (rootBinding != null) {
return RootNode.Binding(rootBinding)
}
结论 (Conclude)
目前AGP 7.2.0 处理ViewBinding生成代码的方式,虽然aar的模块在生成aar的阶段,已经生成了XxxBinding.java文件,但是由于没有运行ViewBinding相关的Gradle Task,导致依赖aar的模块没有将aar中的XxxBinding.java加入到后续配置查询的binding list中,最终该类型被忽略,默认返回了View类型
替代方法 (Workaround)
由于底层插件的限制,我们没有办法直接使用XxxBinding (或者说时间成本高,没有必要自己手动写一个生成代码的插件),但是我们依然可以映射出XxxBinding
// Activity.kt
class Activity {
private val includedButtonsBinding :IncludedButtonsBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val rootBinding = ActivityAwesomeBinding.inflate(inflater, container, false)
includedButtonsBinding = IncludedButtonsBinding.bind(ActivityAwesomeBinding.includes)
return rootBinding.root
}
}