You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多模块项目中使用ViewBinding填充RecyclerView项视图遇空指针异常

多模块Android应用ViewBinding加载布局时出现NullPointerException问题

问题背景

我有一个多模块Android应用,ui模块中包含RecyclerView要展示的项布局,checkout模块的CheckoutFragment包含该RecyclerView。使用ViewBinding加载布局时出现NullPointerException,但传统findViewById方式加载正常,调试发现add_item、remove_item和quantity_selector对应的视图为null,其余视图可正常初始化。

CheckoutFragment代码

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding.checkoutCartList.layoutManager = LinearLayoutManager(requireContext())
    binding.checkoutCartList.adapter = CheckoutAdapter(arrayOf(CartItem("xxx", 1, "9,99 €")))
}

CheckoutAdapter代码

class CheckoutAdapter(private val list: Array<CartItem>) : RecyclerView.Adapter<CheckoutAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemCheckoutCartProductBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        viewHolder.bind(list[position])
    }

    override fun getItemCount() = list.size

    class ViewHolder(private val binding: ItemCheckoutCartProductBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(item: CartItem) {

        }
    }
}

异常信息

java.lang.NullPointerException: Missing required view with ID: it.xxxx.app.dev:id/add_item
at it.xxxx.ui.databinding.ItemCheckoutCartProductBinding.bind(ItemCheckoutCartProductBinding.java:155)
at it.xxxx.ui.databinding.ItemCheckoutCartProductBinding.inflate(ItemCheckoutCartProductBinding.java:87)

ItemCheckoutCartProduct布局代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/view_32dp_space">

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/card_image_left"
        android:layout_width="@dimen/view_128dp_space"
        android:layout_height="@dimen/view_128dp_space"
        app:cardCornerRadius="@dimen/view_16dp_space"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:strokeColor="@color/colorGrey"
        app:strokeWidth="1dp">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/product_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/view_16dp_space"
            android:src="@drawable/ic_thumb_up_red" />
    </com.google.android.material.card.MaterialCardView>


    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/product_description"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/view_24dp_space"
        android:fontFamily="@font/font_family_bold"
        android:textColor="@android:color/black"
        android:textSize="@dimen/text_16sp_size"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintStart_toEndOf="@id/card_image_left"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/quantity_selector"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/view_24dp_space"
        android:layout_marginTop="@dimen/view_8dp_space"
        app:cardCornerRadius="@dimen/view_24dp_space"
        app:layout_constraintStart_toEndOf="@id/card_image_left"
        app:layout_constraintTop_toBottomOf="@id/product_description"
        app:strokeColor="@color/colorGrey"
        app:strokeWidth="1dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/view_8dp_space"
            android:orientation="horizontal"
            android:weightSum="3">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/remove_item"
                android:layout_width="@dimen/view_12dp_space"
                android:layout_height="@dimen/view_12dp_space"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:scaleType="centerInside"
                android:src="@drawable/ic_minus"
                android:tint="@color/colorGrey" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/product_quantity"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:layout_marginHorizontal="@dimen/view_16dp_space"
                android:layout_weight="1"
                android:fontFamily="@font/font_family_bold"
                android:textColor="@android:color/black"
                android:textSize="@dimen/text_14sp_size"
                tools:text="1" />

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/add_item"
                android:layout_width="@dimen/view_12dp_space"
                android:layout_height="@dimen/view_12dp_space"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:scaleType="centerInside"
                android:src="@drawable/ic_add"
                android:tint="@color/colorGrey" />

        </LinearLayout>
    </com.google.android.material.card.MaterialCardView>

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/delete_product_from_cart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="@dimen/view_24dp_space"
        android:layout_marginTop="@dimen/view_24dp_space"
        android:fontFamily="@font/font_family_regular"
        android:text="@string/common_delete"
        android:textSize="@dimen/text_12sp_size"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/card_image_left"
        app:layout_constraintTop_toBottomOf="@id/quantity_selector" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/total_product_price_amount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fontFamily="@font/font_family_bold"
        android:textColor="@android:color/black"
        android:textSize="@dimen/text_16sp_size"
        app:layout_constraintBottom_toBottomOf="@id/delete_product_from_cart"
        app:layout_constraintEnd_toEndOf="parent"
        tools:text="4,20$" />


</androidx.constraintlayout.widget.ConstraintLayout>

问题原因及解决方案

核心原因

这是多模块环境下资源ID冲突或ViewBinding绑定类引用错误模块资源导致的:

  • 若checkout模块和ui模块存在同名的资源ID(哪怕在不同布局中),Gradle合并资源时会覆盖ui模块的资源,导致ViewBinding查找不到正确的视图。
  • ViewBinding生成的绑定类可能混淆了模块的资源命名空间,导致加载布局时引用了错误模块的资源定义。

解决步骤

  1. 排查并修改重复的资源ID
    搜索add_item、remove_item、quantity_selector这几个ID在所有模块的布局文件中是否存在重复定义,若有则修改ID名称(比如加上模块前缀,如ui_add_item、checkout_add_item)。

  2. 清理缓存并重新构建项目
    执行File -> Invalidate Caches... -> Invalidate and Restart,或在终端运行./gradlew clean build,解决ViewBinding生成的绑定类缓存问题。

  3. 明确指定LayoutInflater的资源命名空间
    在CheckoutAdapter的onCreateViewHolder中,确保加载的是ui模块的布局资源:

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val packageName = parent.context.resources.getResourcePackageName(R.layout.item_checkout_cart_product)
        val inflater = LayoutInflater.from(parent.context).cloneInContext(
            ContextThemeWrapper(parent.context, packageName)
        )
        val binding = ItemCheckoutCartProductBinding.inflate(inflater, parent, false)
        return ViewHolder(binding)
    }
    
  4. 确认模块依赖配置正确
    检查checkout模块的build.gradle,确保对ui模块的依赖为implementation,保证资源可正常访问:

    dependencies {
        implementation project(":ui")
    }
    

内容的提问来源于stack exchange,提问作者giordy16

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 00:59:53