FirebaseRecyclerAdapter doesn't recognize first layout as a position

。_饼干妹妹 提交于 2019-11-28 02:03:23

The ideal solution would have been to set two adapters on a single RecyclerView but unfortunatelly this is not possible. However, you can make a single custom Adapter that handles two types of items. I will explain this by getting an example.

Let's assume you need to display objects of two types, humans and aliens. Your objects require completely different layouts and completely different ViewHolders. Please see the below code for the ViewHolders:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static class HumanViewHolder extends RecyclerView.ViewHolder {
        public HumanViewHolder(View itemView) {
            super(itemView);

            //Prepare your ViewHolder
        }

        public void bind(Human human) {

            //Display your human object
        }
    }

    private static class AlienViewHolder extends RecyclerView.ViewHolder {
        public AlienViewHolder(View itemView) {
            super(itemView);

            //Prepare your ViewHolder
        }

        public void bind(Alien alien) {

            //Display your alien object
        }
    }
}

First you need to add two different constants to your adapter representing both type of views:

private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;

To keep things simple, let's also assume you store your objects in a list:

private List<Object> items = new ArrayList<>();

public MyAdapter(List<Object> items) {
    this.items.addAll(items);

    //Other stuff if needed
}

Now, the first you need to do, is to implement getItemViewType() method:

@Override
public int getItemViewType(int position) {
    if (items.get(position) instanceof Human) {
        return ITEM_TYPE_HUMAN;
    } else {
        return ITEM_TYPE_ALIEN;
    }
} 

Second, you need to use the item type inside the onCreateViewHolder() method like this:

@Override 
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)  {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());

    if (viewType == ITEM_TYPE_HUMAN) {
        View view = layoutInflater.inflate(R.layout.item_human, parent, false);

        return new HumanViewHolder(view);
    } else {      
        View view = layoutInflater.inflate(R.layout.item_alien, parent, false);

        return new AlienViewHolder(view);
    } 
} 

In the end, you just need to bind the proper view holder like this:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    Object item = items.get(position);

    if (viewHolder instanceof HumanViewHolder) {
        ((HumanViewHolder) viewHolder).bind((Human) item);
    } else {
        ((AlienViewHolder) viewHolder).bind((Alien) item);
    } 
} 

Why use the Firebase Recycler Adapter when you could easily make a custom one? If I understood well you want an item to be fixed at position 0 (header) while others will be added below the first one, right? If so, here is a solution I like to use:

public interface ViewType {
    public int getViewType();
}

public interface ViewTypeDelegateAdapter {
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}

public class ViewTypes {
    public static int HEADER = 0
    public static int ITEM = 1
}

public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {

    private int resID;
    private Context context;

    public ProductDelegateAdapter(int resID, Context context) {
        this.resID = resID;
        this.context = context;
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
        return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
        (holder as ProductHolder).bind("test");
    }

    class ProductHolder extends RecyclerView.ViewHolder {

        public ProductHolder(View view) {
            super(view);
        }

        public void bind(String test) {

        }

    }

}

public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {

    private int resID;
    private Context context;

    public ProductDelegateAdapter(int resID, Context context) {
        this.resID = resID;
        this.context = context;
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
        return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
        (holder as HeaderHolder).bind("test");
    }

    class HeaderHolder extends RecyclerView.ViewHolder {

        public HeaderHolder(View view) {
            super(view);
        }

        public void bind(String test) {

        }

    }

}

public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private Context context;
    private List<ViewType> items;
    private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
    private ViewType headerItem;

    public AccAdapter(Context context) {
        this.context = context;
        this.items = new ArrayList();
        this.delegateAdapters = new SparseArrayCompat();
        this.headerItem = new ViewType() {
            @Override
            public int getViewType() {
                return ViewTypes.HEADER;
            }
        };

        this.items.add(this.headerItem);
        this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
        this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
        return delegateAdapters.get(viewType).onCreateViewHolder(parent);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
        delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
    }

    @Override
    public Int getItemViewType(Int position) {
        return items.get(position).getViewType();
    }

    @Override
    public Int getItemCount() {
        return items.getSize();
    }

    public void add(ViewType viewType) {
        val initPosition = this.items.size - 1
        this.items.add(item)
        notifyItemRangeChanged(initPosition, this.items.size + 1)
    }

}

public class Event implements ViewType {

    private String id;

    @Override
    public int getViewType() {
        return ViewTypes.ITEM;
    }

}

Excuse me for some syntax errors, I've translated to Java from Kotlin to help you. Hope it helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!