type ) We will most likely want to inflate additional views for these different view types.
In that case, we will need to override getItemViewType(.
) in order to provide the appropriate viewType argument to the subsequent methods.
Next, additional logic will be required in the onCreateViewHolder(.
Then, we will want to create additional ViewHolders as logic regarding our data might be different.
Here is what it might look like if it all stays in the same file:Don’t forget that in this case we can no longer specify BasicViewHolder as the ViewHolder type when we extend the RecyclerView.
We must use the parent ViewHolder class.
We just doubled the size of our Adapter class.
It’s now easy to imagine how quickly this can escalate and swell to an unwieldy size given any additional view types or logic.
So how do we contain this beast from growing to epic proportions?.We should probably break out the ViewHolder classes into their own files and we will do just that.
However, removing the ViewHolder classes as they are will do little if the logic for each view is complex.
All of that logic presently lives in our onBindViewHolder(.
If only there were a way to move all that code into the ViewHolder class when we break it out.
????The first thing we need to do is create an abstract class for our ViewHolders to implement.
Behold the BaseViewHolderClass:We need to create a ViewHolder class and extend the BaseViewHolder; that way, we will have provided a bind method for the adapter to bind the model data to the relevant viewHolder.
We can easily handle all view logic in the ViewHolder once it’s bound in the adapter.
In our adapter’s onBindViewHolder(…) method we can remove the when statement and just tell the holder to bind the data.
It does not matter which type of ViewHolder it is at this point for the bind() method only cares that it gets the data.
Sweet!.This is cleaning up nicely.
What else might we extract?.How about the logic in getItemViewType(.
)?.That would be even sweeter.
Enter the Visitor Pattern.
The Visitor Pattern is one of the many design patterns put to paper by the Gang of Four (Four dudes who wrote a highly influential book called Design Patterns: Elements of Reusable Object-Oriented Software in the 90s.
It’s still highly relevant in case there is any concern on that matter).
The Visitor Pattern also allows us to adhere to the Open/Closed principle (the O of the S.
principles: Open to extension, closed to modification).
Thus we extend functionality of the adapter without having to change it.
Our goal here is to be able to add as many view types as we like without having to ever change code in the adapter.
We are already very close to getting the adapter to that state but before we can, we need to set up a few other things.
First, let’s modify the Item model.
Item must be able to be “visited” so that some typeFactory may determine the item’s type.
For the sake of keeping it D.
, let’s create an interface called ItemViewModel that will allow all of our models to accept a visitor to determine that model’s type.
Now we need to implement it in the Item model.
Our Item model got some new stuff.
It’s now the owner of all the information pertaining to itself such as what types it can be and what views it can occupy.
Seems reasonable, right?The ViewHolderTypeFactory (The Visitor) … and a bit more.
The idea is that an Item object will have a method that accepts the viewHolderTypeFactory and returns the appropriate ViewHolder type: val type = item.
In essence, the viewHolderTypeFactory is “visiting” the Item object to determine the ViewHolder type.
Additionally, the primary reason ViewHolderTypeFactory exists should be evident by its name — it needs to produce a ViewHolder.
So we need to implement a create() method that takes the parent view and the view type and creates the appropriate ViewHolder.
That’s it!.Now we can finally refine our adapter to its Open/Closed-compliant state.
Check it out:At scale, this pattern is great for an app that has multiple RecyclerViews that display multiple views.
Once click handlers are introduced, we can add as many view types as needed without having to touch the adapter.
As a final note, each RecyclerView should have its own ViewFactory as it will most likely use different data models than the others.