0

This is my RecyclerView Item Layout

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 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:orientation="vertical"><!--
    android:background="@color/home_item_bg"-->

    <include
        android:id="@+id/layoutSectionHeader"
        layout="@layout/section_header_rv_item_home"/>

    <androidx.cardview.widget.CardView
        style="@style/Widget.MaterialComponents.CardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        app:cardElevation="2dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            android:paddingStart="16dp"
            android:paddingTop="8dp"
            android:paddingEnd="16dp"
            android:paddingBottom="8dp">

            <TextView
                android:id="@+id/tvMarketAndTerm"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textStyle="bold"
                tools:text="NASDAQ - Medium Term" />

            <com.github.mikephil.charting.charts.PieChart
                android:id="@+id/pieChart"
                android:layout_width="match_parent"
                android:layout_height="@dimen/pie_chart_height" />

        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

This is section_header_rv_item_home.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/llSectionHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingStart="16dp"
    android:paddingTop="12dp"
    android:background="?selectableItemBackground"
    android:paddingEnd="16dp"
    android:paddingBottom="12dp"><!--
    android:background="@drawable/ripple_white_light_grey"-->

    <TextView
        android:id="@+id/tvProductName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ellipsize="end"
        android:maxLines="1"
        android:textAllCaps="false"
        android:textColor="@color/gray"
        android:textSize="20sp"
        android:textStyle="bold"
        tools:text="@string/stock_exchange_barometer" />

    <TextView
        android:id="@+id/tvSeeAll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/see_all"
        android:textColor="@color/colorAccent"
        android:textSize="13sp"
        android:textStyle="bold"
        android:visibility="gone"
        tools:visibility="visible" />
</LinearLayout>

This is how'm accessing the views inside the included layout

inner class BarometerVH(private val rvBinding: RvItemHomeSeBarometerBinding) :
            RecyclerView.ViewHolder(rvBinding.root) {
    fun bind(homeItem: HomeItem) {
        rvBinding.layoutSectionHeader.tvProductName.text = homeItem.title
    }
}

I got no compile time error, but getting this exception when I run the app

java.lang.NullPointerException: Missing required view with ID: com.example.appname:id/layoutSectionHeader

Including a layout in Activity or Fragment works for me, but not working when used in Recycler View.

I tried multiple solutions given in this forum for similar exceptions, but none worked for a recycler view and not question regarding using <include inside recycler view.

Edit 1: I've added the overridden methods from the RecyclerView Adapter

override fun onCreateViewHolder(
     parent: ViewGroup,
     viewType: Int
) = MarketCommentaryVH(RvItemHomeMarketCommentaryBinding.bind(parent))

override fun onBindViewHolder(
     holder: RecyclerView.ViewHolder,
     position: Int
) {
    holder.bind(homeItemList[position])
}
  • Hello and please provide a bit more information. Show us (the relevant) parts of your RecyclerView Adapter, and anything related. – Martin Marconcini Apr 06 '21 at 13:03
  • @MartinMarconcini, I added Adapter's overridden methods, please check. You can find the Viewholder in 3rd codeblock. – Vishak A Kamath Apr 06 '21 at 13:13
  • It's strange, but it appears ViewBinding is having troubles with the included layout, perhaps because it doesn't have a unique Id (since it's the same layout that you include over and over). Maybe for that bit, you may have to rely on the old findViewById. I haven't tested this, so I cannot give you at this time better advice. – Martin Marconcini Apr 06 '21 at 13:15
  • I think you need to create a separate binding for included layout. So in bind() fun you should do something like `val layoutSectionHeaderBinding = LayoutSectionHeaderBinding.bind(rvBinding.root)` and than you could reference `tvProductName` – M. Wojcik Apr 06 '21 at 13:19
  • Thanks to @cactustictacs's answer, I realised that I was Directly binding the Layout without Inflating it. – Vishak A Kamath Apr 07 '21 at 10:20

1 Answers1

2

A RecyclerView works by creating and reusing a bunch of ViewHolders, which hold a view layout to display the details of an item. You set these up in the onCreateViewHolder method, where you:

  • inflate a layout for the item
  • pass that inflated view to the ViewHolder constructor

You're not actually inflating the layout though, you're doing

RvItemHomeMarketCommentaryBinding.bind(parent)

instead of

RvItemHomeMarketCommentaryBinding.inflate(LayoutInflater.from(context), parent, false)

(you need to pass in the parent while inflating a ViewHolder's layout, so it can lay itself out with the correct dimensions etc)


The bind function on a Binding component takes an already inflated view hierarchy, and tries to find all the components with the IDs it knows about. So for example it tries to find layoutSectionHeader so it can assign binding.layoutSectionHeader to that view.

Trouble is, that doesn't exist in the parent layout you're passing in, because that's just the RecyclerView's layout, it doesn't contain the stuff from the ViewHolder layout. So bind doesn't work - the views aren't there to bind to. You need to call inflate instead

cactustictacs
  • 17,935
  • 2
  • 14
  • 25