Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle recyclerview click in a fragment instead of holder class

I have a fragment that displays a RecyclerView. I am currently handling the onclick event in my holder class like this:

public class CategoryHolder extends RecyclerView.ViewHolder implements View.OnClickListener  {

    public ImageView categoryImageView;
    public TextView categoryNameTextView;
    public TextView categoryAmountTextView;
    ArrayList<Category> categoriesArrayList = new ArrayList<>();
    Context context;


    public CategoryHolder(View itemView, Context context, ArrayList<Category> categories) {
        super(itemView);
        this.categoriesArrayList = categories;
        this.context = context;

        itemView.setOnClickListener(this);
        this.categoryImageView = (ImageView) itemView.findViewById(R.id.categoryImageView);
        this.categoryNameTextView = (TextView) itemView.findViewById(R.id.categoryNameTextView);
        this.categoryAmountTextView = (TextView) itemView.findViewById(R.id.categoryAmountTextView);
    }


    @Override
    public void onClick(View v) {

        int position = getAdapterPosition();
        Category category = this.categoriesArrayList.get(position);
        Toast.makeText(context, ""+category.getCategoryName() + position, 


    }
}

As you can see I have implemented OnClickListener in the holder class and then setTheOnItemClickListner in the Holder.

In my Adapter I pass the holder class the the arraylist with the data like this:

 Context context;
    ArrayList<Category> categories;


    public CategoriesAdapter(Context context, ArrayList<Category> categories) {
        this.context = context;
        this.categories = categories;
    }

    @Override
    public CategoryHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.categorylist_singlecell, parent, false);
        CategoryHolder holder = new CategoryHolder(v, context, categories);
        return holder;
    }

I am passing the data when creating the new holder.

This works fine and I can toast the position and any of the data from the ArrayList that is used for the RecyclerView.

What I want to do though is use that in the main fragment where I initialise the RecyclerView and adapter.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_nested_youtube_video_selection, container, false);

    //////////////////////////// CATEGORIES RECYCLER /////////////////////////////////////

    // Initialise the categories Recylerview
    LinearLayoutManager categoriesLayoutManger = new LinearLayoutManager(getActivity());
    categoriesLayoutManger.setOrientation(LinearLayoutManager.HORIZONTAL);
    categoriesRecyclerView = (RecyclerView) view.findViewById(R.id.youtubeAlarmCategoryRecyclerView);
    categoriesRecyclerView.setLayoutManager(categoriesLayoutManger);

    // Get the data for the categories RecyclerView
    categoryArraylist = CategoryCollection.getCategoryArrayList();

    // Initialse the categories RecyclerView Adapter
    categoriesAdapter = new CategoriesAdapter(getActivity(), categoryArraylist);

    // Bind the categories Adapter to the categories RecyclerView
    categoriesRecyclerView.setAdapter(categoriesAdapter);

I am thinking I need an interface but I am not sure how to do that or if that is even the best way to do it.

like image 632
Nicholas Muir Avatar asked Feb 06 '23 00:02

Nicholas Muir


1 Answers

Following should work:

  • create an interface
  • create an instance of this interface in your fragment and pass it on to the adapter
  • let the adapter pass this interface on to the view holder
  • let the view holder define an onClickListener that passes the event on to the interface

Here's an example:

Interface

public interface ItemClickListener {

    void onItemClicked(ViewHolder vh, Object item, int pos);
}

public interface GenericItemClickListener<T, VH extends ViewHolder> {

    void onItemClicked(VH vh, T item, int pos);
}

ViewHolder

public class CategoryHolder extends RecyclerView.ViewHolder {

    public CategoryHolder(View itemView, Context context) {
        super(itemView);
        this.context = context;

        this.categoryImageView = (ImageView) itemView.findViewById(R.id.categoryImageView);
        this.categoryNameTextView = (TextView) itemView.findViewById(R.id.categoryNameTextView);
        this.categoryAmountTextView = (TextView) itemView.findViewById(R.id.categoryAmountTextView);
    }
}

Adapter

Context context;
ArrayList<Category> categories;
ItemClickListener itemClickListener;

public CategoriesAdapter(Context context, ArrayList<Category> categories, ItemClickListener itemClickListener) {
    this.context = context;
    this.categories = categories;
    this.itemClickListener = itemClickListener;
}

// DON'T PASS YOUR DATA HERE, just create a ViewHolder
@Override
public CategoryHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.categorylist_singlecell, parent, false);
    CategoryHolder holder = new CategoryHolder(v, context);
    return holder;
}

//HERE you bind one item of your list to the view holder
@Override
public void onBindViewHolder(final CategoryHolder vh, final int i) {
    final Category category = categories.get(i);

    // set click listener
    vh.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            itemClickListener.onItemClicked(vh, category, i);
        }
    });

   // update images and texts...
}

Edit

Updated the code to show you, that you should not pass a array of items to every view holder... The view holder gets created and reused, only update the view holder in onBindViewHolder and bind the view holder instance to the correct data there...

Btw, I would make a generic interface instead, that's even more beautiful... My example is just a simple solution...

Edt 2 - How to create the interface instance

ItemClickListener listener = new ItemClickListener(){
    @Override
    public void onItemClicked(RecyclerView.ViewHolder vh, Object item, int pos){
        Toast.makeText(getActivity(), "Item clicked: " + pos, Toast.LENGTH_SHORT).show();
    }
};
like image 64
prom85 Avatar answered Feb 08 '23 15:02

prom85