Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way of Android View Binding in the RecyclerView adapter class?

Here is the code I used in my RecycleView adapter class. I don't know this is the right way or not to use View Binding. If you have a better solution answer me. Thank you.

@Override
public CategoryAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.common_circle_image, parent, false);

    return new MyViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull CategoryAdapter.MyViewHolder holder, final int position) {
    holder.binding.img.setBackgroundResource(addAdapterData.get(position).getItemUrl());
    holder.binding.txt.setText(addAdapterData.get(position).getItemName());
}

@Override
public int getItemCount() {
    return addAdapterData.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder {

    CommonCircleImageBinding binding;

    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        binding = CommonCircleImageBinding.bind(itemView);
        binding.cardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                commonItemClick.onItemClick(getAdapterPosition(),"");
            }
        });
    }
}

Also, I want to know is it right to use R.layout.layout_name and ViewBinding in the same class.

like image 709
Vijay Villiers Avatar asked Mar 13 '20 03:03

Vijay Villiers


People also ask

What is data binding and view binding in Android?

View binding and data binding both generate binding classes that you can use to reference views directly. However, view binding is intended to handle simpler use cases and provides the following benefits over data binding: Faster compilation: View binding requires no annotation processing, so compile times are faster.

How do I set my adapter binding?

To create a custom binding adapter, you need to create an extension function of the view that will use the adapter. Then, you add the @BindingAdapter annotation. You have to indicate the name of the view attribute that will execute this adapter as a parameter in the annotation.


3 Answers

What you need to do is pass the generated binding class object to the holder class constructor. In your example, You have common_circle_image XML file for RecyclerView item and the generated class is CommonCircleImageBinding so like this you use the onCreateViewHolder to pass the generated binding class to the ViewHolder class

@NonNull
@Override
public CategoryAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    CommonCircleImageBinding itemBinding = CommonCircleImageBinding .inflate(LayoutInflater.from(parent.getContext()), parent, false);
    return new MyViewHolder(itemBinding);
}

and use the holder class like this so you can use these fields in onBindViewHolder

static class MyViewHolder extends RecyclerView.ViewHolder {
    private TextView txt;
    private ImageView img; 

    MyViewHolder(CommonCircleImageBinding itemBinding) {
        super(itemBinding.getRoot());
        img = itemBinding.img ;
        txt = itemBinding.txt ;
    }
}
like image 91
Somesh Kumar Avatar answered Oct 28 '22 23:10

Somesh Kumar


Here is full view binding recycler view code in java, you can do as like:

package com.jbws.myviewbindingdemo.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.jbws.myviewbindingdemo.databinding.RowXmlViewBinding;
import com.jbws.myviewbindingdemo.pojo.ModelObject;

import java.util.ArrayList;

public class RecyclerViewListAdapter extends RecyclerView.Adapter<RecyclerViewListAdapter.ViewHolder> {
    public ArrayList<ModelObject> modelObjectArrayList;

    public RecyclerViewListAdapter(ArrayList<ModelObject> modelObjectArrayList) {
        this.modelObjectArrayList = modelObjectArrayList;
    }

    @NonNull
    @Override
    public RecyclerViewListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(RowXmlViewBinding.inflate(LayoutInflater.from(parent.getContext()),
                parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerViewListAdapter.ViewHolder holder, final int position) {
        ModelObject modelObject = modelObjectArrayList.get(position);
        holder.rowXmlViewBinding.txtObjectName.setText(modelObject.getFullName());
        holder.rowXmlViewBinding.btnUpdateName.setOnClickListener(view -> {
         Log.i("LOG_TAG", "Full Name: " + modelObject.getFullName);
        });
    }

    @Override
    public int getItemCount() {
        return modelObjectArrayList == null ? 0 :
                modelObjectArrayList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private RowXmlViewBinding rowXmlViewBinding;

        public ViewHolder(RowXmlViewBinding rowXmlViewBinding) {
            super(rowXmlViewBinding.getRoot());
            this.rowXmlViewBinding = rowXmlViewBinding;
        }
    }
}
like image 23
Mayur Misal Avatar answered Oct 28 '22 21:10

Mayur Misal


For the folks looking for a solution in Kotlin, here it is:

It's a minimal example, where the adapter gets an array of Strings and displays each of the them in a layout called recyclerview_item in a TextView called itemTextView.

It's based on @SomeshKumar's answer and answers @Vijay Villiers question on how to get rid of the private TextView txt;

Edit: New Version: I noticed the generated ...Binding has a .bind() function, so let's use it. (I guess it might be less resource-heavy?)

class SampleAdapter(private val context: Context, private val content: Array<String>) :
        RecyclerView.Adapter<SampleAdapter.CustomViewHolder>()
{
    class CustomViewHolder(view: View) : RecyclerView.ViewHolder(view)

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int) =
            CustomViewHolder(
                    // Alternatively inflate like usual, if you don't need binding
                    RecyclerviewItemBinding
                            .inflate(LayoutInflater.from(context), viewGroup, false)
                            .root
            )

    override fun getItemCount() = content.size

    override fun onBindViewHolder(viewHolder: CustomViewHolder, position: Int)
    {
        RecyclerviewItemBinding.bind(viewHolder.itemView).apply{
            itemTextView.text = content[position]
            
        }
    }
} 

Edit: Old Version:

class SampleAdapter(private val context: Context, private val content: Array<String>) :
        RecyclerView.Adapter<SampleAdapter.CustomViewHolder>()
{
    class CustomViewHolder(var viewBinding: RecyclerviewItemBinding) :
            RecyclerView.ViewHolder(viewBinding.root)

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int) =
            CustomViewHolder(
                    RecyclerviewItemBinding
                            .inflate(LayoutInflater.from(context), viewGroup, false)
            )

    override fun getItemCount() = content.size

    override fun onBindViewHolder(viewHolder: CustomViewHolder, position: Int)
    {
        viewHolder.viewBinding.apply {
            itemTextView.text = content[position]
        }
    }
}
like image 7
m.reiter Avatar answered Oct 28 '22 23:10

m.reiter