/*
* Copyright (c) 2015 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com>
* All Rights Reserved.
*/
package me.zhanghai.android.douya.ui;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import me.zhanghai.android.douya.util.LogUtils;
public class MergeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerView.Adapter[] mAdapters;
private Map<Integer, Integer> mItemViewTypeToAdapterIndexMap = new HashMap<>();
public MergeAdapter(RecyclerView.Adapter... adapters) {
mAdapters = adapters;
for (RecyclerView.Adapter adapter : mAdapters) {
adapter.registerAdapterDataObserver(new AdapterDataObserver(adapter));
}
boolean hasStableIds = true;
for (RecyclerView.Adapter adapter : mAdapters) {
if (!adapter.hasStableIds()) {
hasStableIds = false;
LogUtils.w("not all adapters have stable ids: " + adapter);
}
}
super.setHasStableIds(hasStableIds);
}
public RecyclerView.Adapter[] getAdapters() {
return mAdapters;
}
@Override
public void setHasStableIds(boolean hasStableIds) {
throw new UnsupportedOperationException("cannot set hasStableIds on MergeAdapter");
}
@Override
public int getItemCount() {
int count = 0;
for (RecyclerView.Adapter adapter : mAdapters) {
count += adapter.getItemCount();
}
return count;
}
@Override
public long getItemId(int position) {
int adapterIndex = 0;
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
return 31 * adapterIndex + adapter.getItemId(position);
} else {
position -= count;
++adapterIndex;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public int getItemViewType(int position) {
int adapterIndex = 0;
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
int itemViewType = (adapterIndex << 16) + adapter.getItemViewType(position);
mItemViewTypeToAdapterIndexMap.put(itemViewType, adapterIndex);
return itemViewType;
} else {
position -= count;
++adapterIndex;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Integer adapterIndex = mItemViewTypeToAdapterIndexMap.get(viewType);
if (adapterIndex != null) {
return mAdapters[adapterIndex].onCreateViewHolder(parent,
viewType - (adapterIndex << 16));
}
throw new IllegalStateException("Unknown viewType: " + viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
//noinspection unchecked
adapter.onBindViewHolder(holder, position);
return;
} else {
position -= count;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position,
List<Object> payloads) {
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
//noinspection unchecked
adapter.onBindViewHolder(holder, position, payloads);
return;
} else {
position -= count;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
int viewType = holder.getItemViewType();
Integer adapterIndex = mItemViewTypeToAdapterIndexMap.get(viewType);
if (adapterIndex != null) {
//noinspection unchecked
mAdapters[adapterIndex].onViewRecycled(holder);
return;
}
throw new IllegalStateException("Unknown viewType: " + viewType);
}
@Override
public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) {
int position = holder.getAdapterPosition();
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
//noinspection unchecked
return adapter.onFailedToRecycleView(holder);
} else {
position -= count;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
int position = holder.getAdapterPosition();
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
//noinspection unchecked
adapter.onViewAttachedToWindow(holder);
return;
} else {
position -= count;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
int position = holder.getAdapterPosition();
for (RecyclerView.Adapter adapter : mAdapters) {
int count = adapter.getItemCount();
if (position < count) {
//noinspection unchecked
adapter.onViewDetachedFromWindow(holder);
return;
} else {
position -= count;
}
}
throw new IllegalStateException("Unknown position: " + position);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
for (RecyclerView.Adapter adapter : mAdapters) {
adapter.onAttachedToRecyclerView(recyclerView);
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
for (RecyclerView.Adapter adapter : mAdapters) {
adapter.onDetachedFromRecyclerView(recyclerView);
}
}
private class AdapterDataObserver extends RecyclerView.AdapterDataObserver {
private RecyclerView.Adapter mAdapter;
public AdapterDataObserver(RecyclerView.Adapter adapter) {
mAdapter = adapter;
}
@Override
public void onChanged() {
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(getItemPosition(positionStart), itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
notifyItemRangeChanged(getItemPosition(positionStart), itemCount, payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
notifyItemRangeInserted(getItemPosition(positionStart), itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
notifyItemRangeRemoved(getItemPosition(positionStart), itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
if (itemCount != 1) {
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
}
notifyItemMoved(getItemPosition(fromPosition), getItemPosition(toPosition));
}
private int getItemPosition(int position) {
for (RecyclerView.Adapter adapter : mAdapters) {
if (adapter == mAdapter) {
break;
} else {
position += adapter.getItemCount();
}
}
return position;
}
}
}