跳转至

RecyclerView

简化Adapter

在实际的开发中,我们的项目中可能存在多个列表,每个列表都必须创建一个Adapter。每一个Adapter都有大量的重复代码,比如onCreateViewHolder方法,每个adapter的操作都差不多,获取view,然后创建一个ViewHolder并返回。我们可以保留相同的操作,将不同的操作抽取出来,达到简化代码的效果。

下面是我进行抽取和封装一个BaseRecyclerViewAdapter:

public abstract class BaseRecyclerViewAdapter<T> extends RecyclerView.Adapter {
    private List<T> mList;
    private Context mContext;
    private OnItemClickListener mOnItemClickListener;
    public static final int TYPE_HEADER = 100;
    public static final int TYPE_FOOTER = 101;
    private List<View> mHeaders = new ArrayList<>();
    private List<View> mFooters = new ArrayList<>();
    public interface OnItemClickListener {
        void onItemClick(View v, int position);
    }
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }
    public BaseRecyclerViewAdapter(Context context, List<T> list) {
        mContext = context;
        mList = list;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType != TYPE_HEADER && viewType != TYPE_FOOTER) {
            AdapterItem<T> item = createAdapterItem();
            View view = LayoutInflater.from(mContext).inflate(item.getLayoutResId(viewType), parent, false);
            return new ViewHolder(view, createAdapterItem());
        } else {
            FrameLayout frameLayout = new FrameLayout(parent.getContext());
            frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            return new HeaderFooterViewHolder(frameLayout);
        }
    }
    public abstract AdapterItem<T> createAdapterItem();
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (isHeader(position)) {
            View v = mHeaders.get(position);
            prepareHeaderFooter((HeaderFooterViewHolder) holder, v);
        } else if (isFooter(position)) {
            View v = mFooters.get(position - mList.size() - mHeaders.size());
            prepareHeaderFooter((HeaderFooterViewHolder) holder, v);
        } else {
            T t = mList.get(position - mHeaders.size());
            ((ViewHolder) holder).item.bindData(mContext, position, t, getItemViewType(position));
            if (mOnItemClickListener != null) {
                holder.itemView.setOnClickListener(v -> {
                    mOnItemClickListener.onItemClick(v, position);
                });
            }
        }
    }
    private void prepareHeaderFooter(HeaderFooterViewHolder vh, View view) {
        if (view.getParent() != null) {
            ((ViewGroup) view.getParent()).removeView(view);
        }
        vh.base.removeAllViews();
        vh.base.addView(view);
    }
    @Override
    public int getItemCount() {
        return mHeaders.size() + mList.size() + mFooters.size();
    }
    private boolean isHeader(int position) {
        return (position < mHeaders.size());
    }
    private boolean isFooter(int position) {
        return (position >= mHeaders.size() + mList.size());
    }
    @Override
    public int getItemViewType(int position) {
        if (isHeader(position)) {
            return TYPE_HEADER;
        } else if (isFooter(position)) {
            return TYPE_FOOTER;
        } else {
            T t = mList.get(position - mHeaders.size());
            return createViewType(position, t);
        }
    }
    public abstract int createViewType(int position, T t);
    public boolean hasFooter() {
        return mFooters.size() > 0;
    }
    public void addHeader(View header) {
        if (!mHeaders.contains(header)) {
            mHeaders.add(header);
            notifyItemInserted(mHeaders.size() - 1);
        }
    }
    public void removeHeader(View header) {
        if (mHeaders.contains(header)) {
            notifyItemRemoved(mHeaders.indexOf(header));
            mHeaders.remove(header);
        }
    }
    public void addFooter(View footer) {
        if (!mFooters.contains(footer)) {
            mFooters.add(footer);
            notifyItemInserted(mHeaders.size() + mList.size() + mFooters.size() - 1);
        }
    }
    public void removeFooter(View footer) {
        if (mFooters.contains(footer)) {
            notifyItemRemoved(mHeaders.size() + mList.size() + mFooters.indexOf(footer));
            mFooters.remove(footer);
        }
    }
    static class ViewHolder<T> extends RecyclerView.ViewHolder {
        protected AdapterItem<T> item;
        protected ViewHolder(View itemView, AdapterItem<T> item) {
            super(itemView);
            this.item = item;
            this.item.bindViews(itemView);
        }
    }

    public static class HeaderFooterViewHolder extends RecyclerView.ViewHolder {
        FrameLayout base;
        public HeaderFooterViewHolder(View itemView) {
            super(itemView);
            base = (FrameLayout) itemView;
        }
    }
}

我们通过观察可以发现,每个Adapter不同的地方就是布局文件不同和绑定数据不一样。我们封装了一个AdapterItem的类来处理这些不同的操作。

1
2
3
4
5
6
public interface AdapterItem<T> {
    @LayoutRes
    int getLayoutResId(int viewType);//获取布局文件的id
    void bindViews(final View root);//进行findViewById的操作
    void bindData(Context context, int position, T t, int viewType);//绑定数据
}

多个不同的列表我们就不需要创建多个Adapter,只需要实现自己的AdapterItem传给BaseRecyclerViewAdapter即可。AdapterItem相比创建一个Adapter代码量少很多。

//实现自己的AdapterItem
public class FeedBackAdapterItem implements AdapterItem<FeedBackMessage> {
    @BindView(R.id.tv_user_name) TextView mUserName;
    @Override
    public int getLayoutResId(int viewType) {
        if (viewType == 0) {
            return R.layout.left_message_item;
        }
        return R.layout.right_message_item;
    }
    @Override
    public void bindViews(View root) {
        ButterKnife.bind(this, root);
    }
    @Override
    public void bindData(Context context, int position, FeedBackMessage feedBackMessage, int viewType) {
        mUserName.setText(feedBackMessage.nickname);
    }
}
//创建Adapter
BaseRecyclerViewAdapter adapter = new BaseRecyclerViewAdapter<FeedBackMessage>(this, mFeedBackMessageList) {
    @Override
    public AdapterItem<FeedBackMessage> createAdapterItem() {
        FeedBackAdapterItem adapterItem = new FeedBackAdapterItem();
        adapterItem.setOnThumbClickListener(FeedBackActivity.this);
        return adapterItem;
    }
    @Override
    public int createViewType(int position, FeedBackMessage message) {
        return message.is_admin == 1 ? 0 : 1;
    }
};

更多阅读