Android ViewBinding 處理<include />標(biāo)簽問題

概述 (Summary)

最近在項(xiàng)目中,遇到一個(gè)關(guān)于使用ViewBinding的問題

在使用<include />標(biāo)簽且layout的文件來(lái)自aar中的文件時(shí),
生成的ViewBinding中映射layout的類型是View,而不是我們期望的XxxBinding,
但是如果layout文件來(lái)自同一個(gè)工程中的另一個(gè)module,則會(huì)生成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)

  • 對(duì)比正常生成和非正常生成時(shí), gradle tasks的執(zhí)行情況

    當(dāng)layout文件在同工程的另一個(gè)module中,能夠正常生成XxxBinding類型時(shí),會(huì)多執(zhí)行該module的相關(guān)tasks:
    dataBindingMergeDependencyArtifactsDebug
    dataBindingMergeGenClassesDebug
    dataBindingGenBaseClassesDebug

  • 分析Android Gradle Plugin源碼

    android.databinding.tool.writer.ViewBinderKt#toViewBinder 該方法直接忽略了aar中l(wèi)ayout對(duì)應(yīng)的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)
        }

結(jié)論 (Conclude)

目前AGP 7.2.0 處理ViewBinding生成代碼的方式,雖然aar的模塊在生成aar的階段,已經(jīng)生成了XxxBinding.java文件,但是由于沒有運(yùn)行ViewBinding相關(guān)的Gradle Task,導(dǎo)致依賴aar的模塊沒有將aar中的XxxBinding.java加入到后續(xù)配置查詢的binding list中,最終該類型被忽略,默認(rèn)返回了View類型

替代方法 (Workaround)

由于底層插件的限制,我們沒有辦法直接使用XxxBinding (或者說時(shí)間成本高,沒有必要自己手動(dòng)寫一個(gè)生成代碼的插件),但是我們依然可以映射出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
    }
}

其他 (others)

Google官方文檔推薦ViewBinding學(xué)習(xí)博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容