Skip to content

Instantly share code, notes, and snippets.

Created November 24, 2019 21:02
Show Gist options
  • Save aubryll/f70b81bfa5ff86cdb4efd86148d60163 to your computer and use it in GitHub Desktop.
Save aubryll/f70b81bfa5ff86cdb4efd86148d60163 to your computer and use it in GitHub Desktop.
This is the Java version of NickHolcombe's ListAdapterWithHeader which was originally wrote in Kotlin, after spending countless hours online looking for a way to add a header to my PagedListAdapter I finally found a solution except it was in Kotlin, I managed to rewrite it in …
import androidx.recyclerview.widget.AsyncDifferConfig;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListUpdateCallback;
import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import kotlin.jvm.internal.Intrinsics;
* {@link RecyclerView.Adapter RecyclerView.Adapter} base class based on
* {@link ListAdapter} for presenting List data with header rows in a
* {@link RecyclerView}, including computing diffs between Lists on a background thread.
* @param <T> Type of the Lists this Adapter will receive.
* @param <VH> A class that extends ViewHolder that will be used by the adapter.
* @param diffCallback DiffUtil.ItemCallback<T> class used by DiffUtils for comparing <T> items
* @param headerOffset Int number of header rows before list
public abstract class ListAdapterWithHeader<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private int headerOffset = 1;
private AsyncListDiffer<T> asyncListDiffer;
public ListAdapterWithHeader(DiffUtil.ItemCallback<T> diffCallback) {
this.asyncListDiffer = new AsyncListDiffer<>(new OffsetListUpdateCallback(this, headerOffset),
new AsyncDifferConfig.Builder<>(diffCallback).build());
public void submitList(List<T> items) {
private List<T> getCurrentList() {
return asyncListDiffer.getCurrentList();
public final T getItem(int position) {
return this.asyncListDiffer.getCurrentList().get(position - this.headerOffset);
public int getItemCount() {
return this.asyncListDiffer.getCurrentList().size() + this.headerOffset;
private final class OffsetListUpdateCallback implements ListUpdateCallback {
private final RecyclerView.Adapter adapter;
private final int offset;
OffsetListUpdateCallback(@NotNull RecyclerView.Adapter adapter, int offset) {
Intrinsics.checkParameterIsNotNull(adapter, "adapter");
this.adapter = adapter;
this.offset = offset;
final int offsetPosition(int originalPosition) {
return originalPosition + this.offset;
public void onInserted(int position, int count) {
this.adapter.notifyItemRangeInserted(this.offsetPosition(position), count);
public void onRemoved(int position, int count) {
this.adapter.notifyItemRangeRemoved(this.offsetPosition(position), count);
public void onMoved(int fromPosition, int toPosition) {
this.adapter.notifyItemMoved(this.offsetPosition(fromPosition), this.offsetPosition(toPosition));
public void onChanged(int position, int count, @Nullable Object payload) {
this.adapter.notifyItemRangeChanged(this.offsetPosition(position), count, payload);
Copy link

Great, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment