Binding in ViewHolder

Nominalista picture Nominalista · Oct 9, 2016 · Viewed 11.9k times · Source

This will be theoretical question.

As everyone we use RecyclerView in many parts of the app. Sometimes RecyclerView contains different items, not only image for example, but ads, hints etc. And that's why we can use getViewType() method in Adapter.

But problem occurs when we have many viewTypes and binding this in Adapter is not elegant. So here is the question, is it nice and good pattern to bind data in ViewHolder?

Let's say we have list of apps.

Every app has name for simplicity. Our ViewHolder looks like this:

class AppViewHolder extends RecyclerView.ViewHolder {

     public TextView nameText;

     AppViewHolder(View itemView) {
          super(itemView)
          nameText = (TextView) itemView.findViewById(R.id.text_name);
     }
}

Now we could add bind method:

public void bind(App app) {
     nameText.setText(app.getName());
}

Is it good pattern?

Another solution would be using ViewModel. Because we have different items in RecyclerView, our Adapter could contain list of class which is base class for every ViewModel.

So basic class is:

class RecyclerViewItem {}

Now class which is ViewModel for App.

class AppRecyclerViewItem extends RecyclerViewItem {

     App app;

     ...
}

and our Adapter just has list of RecyclerViewItems:

class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    List<RecyclerViewItem> items;

    ...
}

So with this approach (I mean using ViewModel) is it better to add bind method in ViewHolder, or in ViewModel?

Answer

R. Zag&#243;rski picture R. Zagórski · Oct 12, 2016

I would say that none of your solutions is good. First one is good only for items, that appear only once in adapter. Creating a method to fill row inside ViewHolder is not a good solution as different type of ViewHolders would grow and your RecyclerView.Adapter would gain more and more lines.

Second method is also not good. Model is the model, should only contain data and not business logic of application.

I would suggest a solution to keep RecyclerView.Adapter clean and pass logic of creating ViewHolder and filling them with data to delegates, that would be registered in ie. RecyclerView.Adapter constructor. This technique is explained more here

This way, registering even over a doven of different ViewHolder does not expecially add boilerplate to RecyclerView.Adapter, but delegates the logic of creating and filling RecyclerView.Adapter rows to those delegates.

But that is just a suggestion.