-
Notifications
You must be signed in to change notification settings - Fork 554
5.x | Item interfaces
- Introduction
- Primary item interfaces
- Additional item interfaces
- Possible combinations
- The importance of
equals
andhashCode
methods
In this page we talk about in the detail of each item interface. For the initial setup please refer to the wiki page Setting Up.
Item interfaces have been introduced to simplify and better organize the code when it comes the necessity to support different item types that are going to be displayed in the RecyclerView. Those items are considered presentation items.
Basically, the Adapter automatically recognizes the view type by mapping the item in a small HashMap, this is done in getItemViewType()
. It then delegates the creation + binding of the ViewHolder to the item itself.
Note: All interfaces are modular and can be combined to add functionalities in the same item.
These items holds some flags, necessary to the Adapter to read the current state of the object.
Basic interface to identify a generic Adapter item. This type returns information for an item to be enabled/disabled, selectable, hidden and touchable. Implement this interface or use AbstractFlexibleItem
. This item also defines the methods for the ViewHolder. In the next wiki page ViewHolders we talk about the creation and the binding of a ViewHolder more in details.
public interface IFlexible<VH extends RecyclerView.ViewHolder> {
/*---------------*/
/* BASIC METHODS */
/*---------------*/
boolean isEnabled();
void setEnabled(boolean enabled);
boolean isHidden();
void setHidden(boolean hidden);
/*--------------------*/
/* SELECTABLE METHODS */
/*--------------------*/
boolean isSelectable();
void setSelectable(boolean selectable);
/*-------------------*/
/* TOUCHABLE METHODS */
/*-------------------*/
boolean isDraggable();
void setDraggable(boolean draggable);
boolean isSwipeable();
void setSwipeable(boolean swipeable);
/*---------------------*/
/* VIEW HOLDER METHODS */
/*---------------------*/
/**
* Returns the layout resource Id to AutoMap a specific ViewType on this Item.
* NOTE: Should identify a resource Layout reference "android.R.layout" used
* by FlexibleAdapter to AutoMap the ViewTypes.
*/
@LayoutRes
int getLayoutRes();
/**
* Creation of the ViewHolder.
*/
VH createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent);
/**
* Binds the data of this item to the given Layout.
*/
void bindViewHolder(FlexibleAdapter adapter, VH holder, int position, List payloads);
}
This Abstract implementation is nothing more than a class that holds the boolean flags and where the equals
method becomes mandatory.
Default values are mEnabled = true
, mHidden = false
, mSelectable = true
, mDraggable = false
, mSwipeable = false
. If you implement directly from IFlexible
, you are instead responsible to provide these values to the Adapter.
Interface to identify an item as able to expand/collapse. In this item we define also the type of the SubItems that are ideally saved in a List. This item already inherits all the methods from IFlexible
interface.
Implement this interface or use AbstractExpandableItem
.
public interface IExpandable<VH extends ExpandableViewHolder, S extends IFlexible>
extends IFlexible<VH> {
/*--------------------*/
/* EXPANDABLE METHODS */
/*--------------------*/
boolean isExpanded();
void setExpanded(boolean expanded);
/**
* Establish the level of the expansion of this type of item in case of multi
* level expansion.
* Default value of first level should return 0.
* Sub expandable items should return a level +1 for each sub level.
*/
int getExpansionLevel();
/*-------------------*/
/* SUB ITEMS METHODS */
/*-------------------*/
List<S> getSubItems();
}
Generic implementation that contains the list of the SubItems and a set of useful methods to handle this list, contains also the boolean flag for the expanded status, plus all the flags inherited from AbstractFlexibleItem
. Default values are mExpanded = false
, mSubItems = null
. If you implement directly from IExpandable
, you are instead responsible to provide these values to the Adapter.
The ViewHolder must be of type ExpandableViewHolder
to benefit of the expandable methods.
Please see the JavaDoc for the entire list of methods this Class is implementing.
Wrapper empty interface to identify if the current item is a Header. Implement this interface or use AbstractHeaderItem
or AbstractExpandableHeaderItem
. The ViewHolder must be of type FlexibleViewHolder
to assure correct Sticky Header behaviours and you are also required to specify sticky=true
to the super ViewHolder constructor.
public interface IHeader<VH extends FlexibleViewHolder> extends IFlexible<VH> {
}
Generic implementation of IHeader
interface. By default this item is hidden and not selectable. The class inherits all the fields and the methods from AbstractFlexibleItem
.
public abstract class AbstractHeaderItem<VH extends FlexibleViewHolder>
extends AbstractFlexibleItem<VH>
implements IHeader<VH> {
/**
* By default, header is hidden and not selectable
*/
public AbstractHeaderItem() {
setHidden(true);
setSelectable(false);
}
}
Complex generic implementation of IExpandable
interface combined with IHeader
interface with useful methods inherited from AbstractExpandableItem
to manage expandable sections with sticky headers and sub items of type ISectionable
.
By default, expandable header is shown, expanded and not selectable.
The ViewHolder must be of type ExpandableViewHolder
to benefit of the expandable methods.
public abstract class AbstractExpandableHeaderItem<VH extends ExpandableViewHolder, S extends ISectionable>
extends AbstractExpandableItem<VH, S>
implements IHeader<VH> {
/**
* By default, expandable header is shown, expanded and not selectable.
*/
public AbstractExpandableHeaderItem() {
setHidden(false);
setExpanded(true);
setSelectable(false);
}
}
Interface that represents an item in a section. Implement this interface or use AbstractSectionableItem
.
public interface ISectionable<VH extends RecyclerView.ViewHolder, T extends IHeader>
extends IFlexible<VH> {
T getHeader();
void setHeader(T header);
}
Generic implementation of ISectionable
interface for items that holds the reference of the header item. If you implement directly from ISectionable
, you are instead responsible to provide the header reference to the Adapter.
These items, instead give some additional features to each item.
By adding this interface to the item signature, the item becomes automatically filterable and when the user start a search, the method filter()
is called by the Adapter. If an item doesn't implement this interface, it is ignored automatically.
public interface IFilterable {
/**
* Checks and performs the filter on this item, you can apply the logic
* and the filter on every fields your use case foreseen.
*
* @param constraint the search text typed by the user
* @return true if this item should be collected by the Adapter for the
* filtered list, false otherwise
*/
boolean filter(String constraint);
}
In case you need item serialization/deserialization OR in case you need to display the same modelData in multiple RecyclerViews managed by different Adapters, you can implement a special item interface to HOLD your data model object!
We separate the real Model object from the Adapter item by using the IHolder
interface as following:
/**
* In this way you can separate the memory zones of the flags (enabled, expanded, hidden,
* selectable, draggable, swipeable, etc...) used by an Adapter, to be independent by
* another Adapter. For instance, an item can be Shown and Expanded in a RV, while in the
* other RV can be Hidden or Not Expanded!
*/
public class CustomItemHolder<Model>
extends AbstractSectionableItem<FlexibleItemHolder.ViewHolder, HeaderItem>
implements IFilterable, IHolder<Model> {
/**
* Your complex data model object
*/
Model modelData;
public CustomItemHolder(Model modelData, HeaderItem header) {
super(header);
this.modelData = modelData;
}
@Override
public Model getModel() {
return modelData;
}
...
}
equals()
and filter()
methods should take into account the fields of Model
class.
Item type to display | Item interfaces to implement |
---|---|
Simple adapter item | IFlexible (AbstractFlexibleItem) |
Expandable item | IFlexible + IExpandable (AbstractExpandableItem) |
SubItem for expandable | IFlexible (AbstractFlexibleItem) |
Header item (with sticky functionality) | IFlexible + IHeader (AbstractHeaderItem) |
Expandable header item (with sticky functionality) | IFlexible + IExpandable + IHeader (AbstractExpandableHeaderItem) |
Section simple item for header | IFlexible + ISectionable (AbstractSectionableItem) |
Section SubItem for expandable header | IFlexible + ISectionable (AbstractSectionableItem) |
Section expandable item for header | IFlexible + ISectionable + IExpandable (AbstractExpandableItem + ISectionable) |
Add filter functionality to any previous item | ... + IFilterable |
Add Model holder functionality to any previous item | ... + IHolder |
It is important to well Override the mandatory equals
method of IFlexible
. Have a look at this page Writing a correct equals method to implement your own equals
method.
You mainly need to implement this method when you have unique IDs for your items. If not, you can rely on default Java implementation return this == o
.
The risk, of a wrong result, is when the Adapter is looking for a reference (Header or sub item) the element is not found and the expected behavior doesn't occur. The equals()
method, which do not check the type of their parameter, may result in latent errors quite difficult to discover!
You should implement also this method if equals
is implemented. This method has several implications that Adapter canl handle better:
- The Hash significantly increases performance in big list during Update & Filter operations, better than the new Android(R) class
DiffUtil
! - You might want to activate stable ids via Constructor for RecyclerView, if your id is unique. More on stable ids? Check issue comment #230 or google it.
Have a look at this page Writing a correct hashCode method to implement your own hashCode
method.
Very simple equals
and hashCode
implementation may be:
public class Item extends AbstractFlexibleItem<Item.ViewHolder> {
private String id;
/**
* When an item is equals to another?
* Write your own concept of equals, mandatory to implement.
*/
@Override
public boolean equals(Object inObject) {
if (inObject instanceof HeaderItem) {
HeaderItem inItem = (HeaderItem) inObject;
return this.id.equals(inItem.id);
}
return false;
}
//... or Java default if you don't have unique IDs.
@Override
public boolean equals(Object o) {
return this == o;
}
/**
* Override this method too, when using functionalities like Filter or CollapseAll.
* FlexibleAdapter is making use of HashSet to improve performance in big list.
*/
@Override
public int hashCode() {
return id.hashCode();
}
}
- Update Data Set
- Selection modes
- Headers and Sections
- Scrollable Headers and Footers
- Expandable items
- Drag&Drop and Swipe
- EndlessScroll / On Load More
- Search Filter
- FastScroller
- Adapter Animations
- Third party Layout Managers
- Payload
- Smooth Layout Managers
- Flexible Item Decoration
- Utils
- ActionModeHelper
- AnimatorHelper
- EmptyViewHelper
- UndoHelper
* = Under revision!