Read the motivation for this project in my blog post.
This library is available on maven central:
compile 'com.hannesdorfmann:adapterdelegates2:2.0.1'Please note that since 2.0 the group id has been changed to adapterdelegates2.
The idea of this library is to build your adapters by composing reusable components.
Favor composition over inheritance
The idea is that you define an AdapterDelegate for each view type. This delegate is responsible for creating ViewHolder and binding ViewHolder for a certain viewtype.
An AdapterDelegate get added to an AdapterDelegatesManager. This manager is the man in the middle between RecyclerView.Adapter and each AdapterDelegate.
For example:
publicclassCatAdapterDelegateimplementsAdapterDelegate<List<Animal>> {
privateLayoutInflaterinflater;
publicCatAdapterDelegate(Activityactivity) {
inflater = activity.getLayoutInflater();
}
@OverridepublicbooleanisForViewType(@NonNullList<Animal> items, intposition) {
returnitems.get(position) instanceofCat;
}
@NonNull@OverridepublicRecyclerView.ViewHolderonCreateViewHolder(ViewGroupparent) {
returnnewCatViewHolder(inflater.inflate(R.layout.item_cat, parent, false));
}
@OverridepublicvoidonBindViewHolder(@NonNullList<Animal> items, intposition,
@NonNullRecyclerView.ViewHolderholder) {
CatViewHoldervh = (CatViewHolder) holder;
Catcat = (Cat) items.get(position);
vh.name.setText(cat.getName());
}
staticclassCatViewHolderextendsRecyclerView.ViewHolder {
publicTextViewname;
publicCatViewHolder(ViewitemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
}
}
}Then an AnimalAdapter could look like this:
publicclassAnimalAdapterextendsRecyclerView.Adapter {
privateAdapterDelegatesManager<List<Animal>> delegatesManager;
privateList<Animal> items;
publicAnimalAdapter(Activityactivity, List<Animal> items) {
this.items = items;
delegatesManager = newAdapterDelegatesManager<>();
// AdapterDelegatesManager internally assigns view types integersdelegatesManager.addDelegate(newCatAdapterDelegate(activity))
.addDelegate(newDogAdapterDelegate(activity))
.addDelegate(newGeckoAdapterDelegate(activity));
// You can explicitly assign integer view type if you want todelegatesManager.addDelegate(23, newSnakeAdapterDelegate(activity));
}
@OverridepublicintgetItemViewType(intposition) {
returndelegatesManager.getItemViewType(items, position);
}
@OverridepublicRecyclerView.ViewHolderonCreateViewHolder(ViewGroupparent, intviewType) {
returndelegatesManager.onCreateViewHolder(parent, viewType);
}
@OverridepublicvoidonBindViewHolder(RecyclerView.ViewHolderholder, intposition) {
delegatesManager.onBindViewHolder(items, position, holder);
}
@OverridepublicintgetItemCount() {
returnitems.size();
}
}As you have seen in the code snipped above this may require to write the same boiler plate code again and again to hook in AdapterDelegatesManager to Adapter.
This can be reduced by extending either from ListDelegationAdapter if the data source the adapter displays is java.util.List<?> or AbsDelegationAdapter which is a more general one (not limited to java.util.List)
For example the same AnimalAdapter from above could be simplified as follows by extending from ListDelegationAdapter:
publicclassAnimalAdapterextendsListDelegationAdapter<List<Animal>> {
publicAnimalAdapter(Activityactivity, List<Animal> items) {
// DelegatesManager is a protected Field in ListDelegationAdapterdelegatesManager.addDelegate(newCatAdapterDelegate(activity))
.addDelegate(newDogAdapterDelegate(activity))
.addDelegate(newGeckoAdapterDelegate(activity))
.addDelegate(23, newSnakeAdapterDelegate(activity));
// Set the items from super class.setItems(items);
}
}Also you may have noticed that you often have to write boilerplate code to cast items and ViewHolders when working with list of items as adapters dataset source.
AbsListItemAdapterDelegate can help you here. Let's take this class to create a CatListItemAdapterDelegate similar to the CatAdapterDelegate from top of this page but without the code for casting items.
publicclassCatListItemAdapterDelegateextendsAbsListItemAdapterDelegate<Cat, Animal, CatViewHolder> {
privateLayoutInflaterinflater;
publicCatAdapterDelegate(Activityactivity) {
inflater = activity.getLayoutInflater();
}
@OverridepublicbooleanisForViewType(Animalitem, List<Animal> items, intposition) {
returniteminstanceofCat;
}
@OverridepublicCatViewHolderonCreateViewHolder(ViewGroupparent) {
returnnewCatViewHolder(inflater.inflate(R.layout.item_cat, parent, false));
}
@OverridepublicvoidonBindViewHolder(Catitem, CatViewHoldervh) {
vh.name.setText(item.getName());
}
staticclassCatViewHolderextendsRecyclerView.ViewHolder {
publicTextViewname;
publicCatViewHolder(ViewitemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
}
}
}As you see, instead of writing code that casts list item to Cat we can use AbsListItemAdapterDelegate to do the same job (by declaring generic types).
What if your adapter's data source contains a certain element you don't have registered an AdapterDelegate for? In this case the AdapterDelegateManager will throw an exception at runtime. However, this is not always what you want. You can specify a fallback AdapterDelegate that will be used if no other AdapterDelegate has been found to handle a certain view type.
AdapterDelegatefallbackDelegate = ...;
adapterDelegateManager.setFallbackDelegate( fallbackDelegate );Note also that boolean return type of isForViewType() of a fallback delegate will be ignored (will not be take into account). So it doesn't matter if you return true or false. You can use AbsFallbackAdapterDelegate that already implements isForViewType() so that you only have to override onCreateViewHolder() and onBindViewHolder() for your fallback adapter delegate.
In contrast to 1.x in 2.0AdapterDelegatesManager internally assigns view type integers automatically for you (you can also explicitly assign view type if you want to). That means that AdapterDelegates.getItemViewType() is no longer needed and has been removed. Therefore, AbsAdapterDelegate is also no longer needed and has been removed too.
To keep version 2.0 backward compatible with project that are already using 1.x the package has been renamed to com.hannesdorfmann.adapterdelegates2 and also the atrifact id has been renamed to adapterdelegates2.
Copyright 2015 Hannes Dorfmann
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.