优化RecylerView实现多种item类型

目录

  • 1.分析需求,利弊。
  • 2.普通adapter实现多种item
  • 4.封装优化adapter

1.需求

  • 目前市面上app 列表展示很多都会存在多种类型布局,比如存在banner区,广告区,图片,新闻等等,IM软件就更不用说,消息类型可达20多种。对于这个问题,RecyclerView可以用ViewType 区分,可以实现需求,但是会存在一些问题:
    • 1.adapter代码过多,不便于扩展
    • 2.不符合开闭原则,多种类型消息,只要新增一种消息类型或者修改bug就需要修改adapter,不便于维护

2.普通adapter的实现

  • 现实多种类型item使用viewType进行区分
  • 代码如下
public class TestAdapter extends RecyclerView.Adapter {

    private List mData;

    private static final int TEXT = 0;
    private static final int AUDIO = 1;
    private static final int IMAGE = 2;


    public TestAdapter(List mData){
        this.mData = mData;
    }

    @NonNull
    @Override
    public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup mViewGroup, int mI) {
        BaseViewHolder baseViewHolder = null;
        switch (mI){
            case TEXT:
                baseViewHolder = new TextViewHolder(LayoutInflater.from(mViewGroup.getContext()).inflate(R.layout.item_text,null));
                break;
            case AUDIO:
                baseViewHolder = new AudioViewHoder(LayoutInflater.from(mViewGroup.getContext()).inflate(R.layout.item_text,null));
                break;
            case IMAGE:
                baseViewHolder = new ImageViewHolder(LayoutInflater.from(mViewGroup.getContext()).inflate(R.layout.item_text,null));
                break;
        }
        return baseViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI) {
        mBaseViewHolder.onBindViewHolder(mBaseViewHolder,mI);
    }

    @Override
    public int getItemViewType(int position) {
        int type = 0;
        switch (mData.get(position).getType()){
            case TEXT:
                break;
            case AUDIO:
                type = 1;
                break;
            case IMAGE :
                type = 2;
                break;
        }
        return type;
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    class AudioViewHoder extends BaseViewHolder{

        public AudioViewHoder(@NonNull View itemView) {
            super(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI) {

        }
    }

    class ImageViewHolder extends BaseViewHolder{

        public ImageViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI) {

        }
    }


    class TextViewHolder extends BaseViewHolder{

        public TextViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI) {

        }
    }

    abstract class BaseViewHolder extends RecyclerView.ViewHolder{
        public BaseViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        public abstract void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI);
    }
}

这是普通的写法,根据getItemViewType区分类型,在type类型不多的时候,这种写法是可取的,但像IM软件中消息列表type类型可达几十种,增加一种消息类型,则需要改动好几处地方,这有点不符合设计原则。而且也没有办法复用该adapter.

4.封装优化adapter

  • 期望:设计一个可以复用,且增加一种type类型或改动type可以不用修改adapter。
  • 重要代码如下:
public abstract class IItemView {

    private T mBaseAdapter;

    public IItemView(T mBaseAdapter){
        this.mBaseAdapter = mBaseAdapter;
    }

    public  abstract int getLayoutId();

    public  abstract void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI,K data);
}

该类用于不同类型item的创建以及数据绑定,也可以说是RecyclerView的ViewHolder。

public class ViewHoderFactory {

    private static HashMap,Class> viewHolders = new HashMap<>();

    static {
        register(TextBean.class,TextViewHolder.class);
        register(AudioBean.class,AudioViewHoder.class);
        register(ImageBean.class,ImageViewHolder.class);
    }

    public static void register(Class bean,Class holder){
        viewHolders.put(bean,holder);
    }

    public static Class getViewHoderType(Class bean){
        return viewHolders.get(bean);
    }

    public static List> getAllViewHoder(){
        return new ArrayList<>(viewHolders.values());
    }
}

该类比较明显,是一个IItemView (也就是ViewHolder)工厂类,用于不同类型的注册,然后用于在adapter中类型区分。

public abstract class BaseAdapter extends RecyclerView.Adapter {

    private List mData;

    private HashMap,Integer> mHashMap = new HashMap<>();
    private SparseArray> holderClasses = new SparseArray<>();

    public BaseAdapter(List mData){
        this.mData = mData;
        List> viewHolders = getIItemViewList();
        for (int i=0;i viewClazz = holderClasses.get(mI);
            Constructor constructor = viewClazz.getConstructors()[0];
            IItemView iItemView = (IItemView) constructor.newInstance(getAdapter());
            return new BaseViewHolder(LayoutInflater.from(mViewGroup.getContext()).inflate(iItemView.getLayoutId(),mViewGroup,false),iItemView,mData);
        }  catch (IllegalAccessException mE) {
            mE.printStackTrace();
        } catch (InstantiationException mE) {
            mE.printStackTrace();
        } catch (InvocationTargetException mE) {
            mE.printStackTrace();
        }
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull BaseViewHolder mBaseViewHolder, int mI) {
        mBaseViewHolder.onBindViewHolder(mBaseViewHolder,mI);
    }

    @Override
    public int getItemViewType(int position) {
        return mHashMap.get(ViewHoderFactory.getViewHoderType(mData.get(position).getClass()));
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    protected abstract T getAdapter();

    protected abstract List> getIItemViewList();

}

该类是一个抽象的adapter,需要新建一个类继承使用。在该adapter中使用ViewHolderFactory区分类型,以及使用反射创建IItemView,只需要在ViewHolderFactory中根据规则 注册不同类型的item,随意增加删减替换顺序都不会影响到adapter,不同类型

的item在各自的Holder中进行数据绑定,实现解耦。

优化后的adapter符合开闭设计原则,便于扩展以及复用。不过仍然还有比较明显的缺陷,也就是ViewHolderFactory,在复用的过程中,需要创建不同的ViewHolderFactory,还会导致静态对象越来越多,还需要进一步的优化。代码已上传github

https://github.com/onelunatic/recycleViewDemo

 

你可能感兴趣的:(优化RecylerView实现多种item类型)