Support adapter wrapping

Tweak your Adapter to support adapter wrapping

Need to tweak several things in your adapter implemtation to support wrapping adapter mechanism. Because WrapperAdapter modifies item positions, item IDs and item view types internally.

» If overriding Adapter.getItemId()

The available range of item ID value is limited, so you cannot use full range of 64-bit integer value. Must return a value greather than or equals to -(2^55) and less than or equals to 2^55 - 1.

Note

This limitation is due to how ItemIdComposer packs other information into 64-bits integer value.

» If overriding Adapter.getItemViewType()

The available range of item view type value is limited, so you cannot use full range of 32-bit integer value. Must return a value greather than or equals to -(2^23) and less than or equals to 2^23 - 1.

Note

This limitation is due to how ItemViewTypeComposer packs other information into 32-bits integer value.

» If using ViewHolder.getAdaperPosition() / ViewHolder.getLayoutPosition())

👉 Use WrapperAdapterUtils.unwrapPosition().

@Overfides
void onClick(View v) {
    RecyclerView rv = RecyclerViewAdapterUtils.getParentRecyclerView(v);
    RecyclerView.ViewHolder vh = rv.findContainingViewHolder(v);

    int rootPosition = vh.getAdapterPosition();
    if (rootPosition == RecyclerView.NO_POSITION) {
        return;
    }

    // need to determine adapter local position like this:
    RecyclerView.Adapter rootAdapter = rv.getAdapter();
    int localPosition = WrapperAdapterUtils.unwrapPosition(rootAdapter, this, rootPosition);

    Item item = mItems.get(localPosition);
    ...
}

» If using ViewHolder.getItemViewType()

👉 Use ItemViewTypeComposer.extractWrappedViewTypePart().

@Overfides
void onClick(View v) {
    RecyclerView.ViewHolder vh = recyclerView.findContainingViewHolder(v);

    int rawViewType = vh.getItemViewType();
    int viewType = ItemIdComposer.extractWrappedIdPart(rawViewType);

    // use "viewType" here to determine which type of item is clicked
    ...
}

» If using ViewHolder.getItemId()

👉 Use ItemIdComposer.extractWrappedIdPart().

@Overfides
void onClick(View v) {
    RecyclerView.ViewHolder vh = recyclerView.findContainingViewHolder(v);

    long rawId = vh.getItemId();
    long id = ItemIdComposer.extractWrappedIdPart(rawId);

    // use "id" here to determine which item is clicked
    ...
}

» If your adapter overrides optional methods of RecyclerView.Adapter

👉 Implement the WrappedAdapter :octocat: interface and use the viewType parameter instead of using ViewHolder.getItemViewType()

This step is only required in case of the adapter overrides the following methods;

class MyInnerAdapter<VH> implements WrappedAdapter<VH> {
    // the following four methods are provided by WrappedAdapter interface
    @Overrides
    void onViewAttachedToWindow(VH holder, int viewType) { ... }

    @Overrides
    void onViewDetachedFromWindow(VH holder, int viewType) { ... }

    @Overrides
    void onViewRecycled(VH holder, int viewType) { ... }

    @Overrides
    boolean onFailedToRecycleView(VH holder, int viewType) { ... }

    // proxy to WrappedAdapter's methods
    @Overrides
    void onViewAttachedToWindow(VH holder) {
        onViewAttachedToWindow(holder, holder.getItemViewType());
    }

    @Overrides
    void onViewDetachedFromWindow(VH holder, int viewType) {
        onViewDetachedFromWindow(holder, holder.getItemViewType());
    }

    @Overrides
    void onViewRecycled(VH holder, int viewType) {
        onViewRecycled(holder, holder.getItemViewType());
    }

    @Overrides
    boolean onFailedToRecycleView(VH holder, int viewType) {
        onFailedToRecycleView(holder, holder.getItemViewType());
    }
}