Android Binding Adapter using same binding name on same View type but for different purpose

1.2k views Asked by At

First, I am new to data binding so please don't judge me for my (possibly dumb) question :). I want to use the same binding name for e.g app:data to a RecyclerView and bind it to a ViewModel field which provides a List<MyModel>. But, I want to use a different Adapter (to inflate different item layout for e.g) for a different instance of RecyclerView.

// For RecyclerView 1
@BindingAdapter("app:data")
fun setData(recyclerView: RecyclerView, data: List<MyModel>?) {
    data?.let {
        recyclerView.adapter = RV1Adapter(data)
    }
}

// For RecyclerView 2
@BindingAdapter("app:data")
fun setData(recyclerView: RecyclerView, data: List<MyModel>?) {
    data?.let {
        recyclerView.adapter = RV2Adapter(data)
    }
}

On a layout for e.g

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rcv1"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    app:data="${viewModel.data}"/>


<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rcv2"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    app:data="${viewModel.data}"/>

How can I achieve this?

Should I use different binding name? (I'm not using this approach before because it will be a little bit messy I think)

Or how is the 'correct' way to do this?

Thank you

2

There are 2 answers

4
Zain On BEST ANSWER

You can't use the same binding adapter tag as both setData() methods have the same signature/parameters, so in layout it can't decide which one to use.

But instead you can use a single method, and differ between both RecyclerViews with their id

@BindingAdapter("app:data")
fun setData(recyclerView: RecyclerView, data: List<MyModel>?) {
    data?.let {
        if (recyclerView.id == R.id.rcv1)
            recyclerView.adapter = RV1Adapter(data)

        else if (recyclerView.id == R.id.rcv2)
            recyclerView.adapter = RV2Adapter(data)
    }
}

2
NhatVM On

I have never applied your solution. I usually create an observer for the data of ViewModel in Fragment and pass it to Adapter.

But I think we still have a solution for your problem. I don't know how you implemented your Adapter. I assume that your adapter is extending from ListAdapter. So instead of initializing your adapter in Binding Adapter, we will initialize it in the Fragment and assign it to Recyclerview. Like this:

// onCreateView method 
val adapter = RV2Adapter()
dataBinding.rcv.adapter = adapter 

and then in the Binding Adapter, we will do like this:

@BindingAdapter("app:data")
fun setData(recyclerView: RecyclerView, data: List<MyModel>?) {
    data?.let {
        recyclerView.adapter.submitList(data)
    }
}

If your adapter isn't extending from ListAdapter. You can create a setter method in its and pass the list of data.

@BindingAdapter("app:data")
    fun setData(recyclerView: RecyclerView, data: List<MyModel>?) {
        data?.let {
            recyclerView.adapter.setData(data)
            recyclerView.adapter.notifyDataChanged()
        }
    }