RecyclerView-->通用的Adapter

weixin_33936401發表於2018-10-12
1775338-c664a8bb3db77112.jpg

打造一個通用的Adapter,可以減少我們的程式碼量,通用的Adapter需要我們考慮三個問題:

  • 資料的型別?我們可以採用泛型;
  • 佈局?我們可以利用建構函式傳遞;
  • 繫結?利用回傳,讓子類實現;

1.Adapter的基本改造

通用Adapter的程式碼如下:

public abstract class CommonRecyclerAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
    protected Context mContext;
    protected LayoutInflater mInflater;
    protected List<T> mDatas;
    private int mLayoutId;

    public CommonRecyclerAdapter(Context context, List<T> datas, int layoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mDatas = datas;
        this.mLayoutId = layoutId;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(mLayoutId, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        if (mDatas != null){
            convert(holder, mDatas.get(position),position);
        }else {
            convert(holder, null,position);
        }
    }

    /**
     * 利用抽象方法回傳出去,每個不一樣的Adapter去設定
     * @param item 當前的資料
     */
    public abstract void convert(ViewHolder holder, T item,int position);

    @Override
    public int getItemCount() {
        return mDatas == null ? 20:mDatas.size();
    }
}

實際使用如下:

public class TestAdapter extends CommonRecyclerAdapter<String> {



    public TestAdapter(Context context, List<String> datas) {
        super(context,datas,R.layout.item_demo);
    }
    @Override
    public void convert(ViewHolder viewHolder, String bean, int position) {
        TextView text = (TextView)viewHolder.itemView.findViewById(R.id.tv_text);
        text.setText(String.format("第%d資料", position + 1));
    }

}

可以看到程式碼量大大滴減少了。

但是上面使用中我們發現每次呼叫onBindViewHolder都會findViewById,所以我們還需要對ViewHolder進行優化。

2.ViewHolder的優化

優化後的ViewHolder如下:

public class ViewHolder extends RecyclerView.ViewHolder {

    //用來存放view減少findviewByid的次數
    private SparseArray<View> mViews;
    public ViewHolder(@NonNull View itemView) {
        super(itemView);
        mViews = new SparseArray<>();
    }

    /**
     * 設定TextView文字
     * @param viewId
     * @param text
     * @return
     */
    public ViewHolder setText(int viewId,CharSequence text){
        TextView tv = getView(viewId);
        tv.setText(text);
        return this;
    }

    public <T extends  View> T getView(int viewId){
        View view = mViews.get(viewId);
        if (view == null){
            view = itemView.findViewById(viewId);
            mViews.put(viewId,view);
        }

        return (T)view;
    }

    /**
     * 設定view是否可見
     * @param viewId
     * @param visibility
     * @return
     */
    public ViewHolder setViewVisibility(int viewId,int visibility){
        getView(viewId).setVisibility(visibility);
        return this;
    }

    /**
     * 設定ImageView資源
     * @param viewId
     * @param resId
     * @return
     */
    public  ViewHolder setImageResourse(int viewId,int resId){
        ImageView imageView = getView(viewId);
        imageView.setImageResource(resId);
        return this;
    }

    /**
     * 設定條目的點選事件
     * @param listener
     */
    public void setOnItemClickListener(View.OnClickListener listener){
        itemView.setOnClickListener(listener);
    }

    /**
     * 設定圖片通過url,載入圖片使用的第三方可能不一樣,所以定義了HolderImageLoader
     * @param viewId
     * @param imageLoader
     */
    public void setImageByUrl(int viewId,HolderImageLoader imageLoader){
        ImageView imageView = getView(viewId);
        if (imageLoader == null){
            throw  new NullPointerException("imageLoader is null!");
        }
        imageLoader.displayImage(imageView.getContext(),imageView,imageLoader.getImagePath());
    }
    /**
     * 設定條目的長按事件
     * @param listener
     */
    public void setOnItemLongClickListener(View.OnLongClickListener listener){
        itemView.setOnLongClickListener(listener);
    }

    public static abstract class HolderImageLoader{
        private String mImagePath;
        public HolderImageLoader(String imagePath){
            this.mImagePath = imagePath;
        }
        public String getImagePath(){
            return mImagePath;
        }

        public abstract void displayImage(Context context,ImageView imageView,String imagePath);
    }
}

實際使用:

public class TestAdapter extends CommonRecyclerAdapter<String> {
    
    public TestAdapter(Context context, List<String> datas) {
        super(context,datas,R.layout.item_demo);
    }
    @Override
    public void convert(ViewHolder viewHolder, String bean, int position) {
        viewHolder.setText(R.id.tv_text,String.format("第%d資料", position + 1))
    }

}

3.多佈局的實現

public interface MultiTypeSupport<T> {
    public int getLayoutId(T bean,int position);
}

最終的Adapter:

public abstract class CommonRecyclerAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
    protected Context mContext;
    protected LayoutInflater mInflater;
    protected List<T> mDatas;
    private int mLayoutId;
    //多佈局支援
    private MultiTypeSupport mMultiTypeSupport;

    public CommonRecyclerAdapter(Context context, List<T> datas, int layoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mDatas = datas;
        this.mLayoutId = layoutId;
    }

    //多佈局支援
    public CommonRecyclerAdapter(Context context, List<T> datas, MultiTypeSupport multiTypeSupport) {
        this(context, datas, -1);
        mMultiTypeSupport = multiTypeSupport;
    }

    @Override
    public int getItemViewType(int position) {
        if (mMultiTypeSupport != null)
            return mMultiTypeSupport.getLayoutId(mDatas.get(position), position);
        return super.getItemViewType(position);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mMultiTypeSupport != null)
            mLayoutId = viewType;
        View itemView = mInflater.inflate(mLayoutId, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        if (mItemClickListener != null) {
            holder.setOnItemClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mItemClickListener.OnItemClick(position);
                }
            });
        }

        if (mLongClickListener != null) {
            holder.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    return mLongClickListener.onLongClick(position);
                }
            });
        }
        if (mDatas != null) {
            convert(holder, mDatas.get(position), position);
        } else {
            convert(holder, null, position);
        }
    }

    /**
     * 利用抽象方法回傳出去,每個不一樣的Adapter去設定
     *
     * @param item 當前的資料
     */
    public abstract void convert(ViewHolder holder, T item, int position);

    @Override
    public int getItemCount() {
        return mDatas == null ? 20 : mDatas.size();
    }

    /***************
     * 設定條目點選和長按事件
     *********************/
    public OnItemClickListener mItemClickListener;
    public OnLongClickListener mLongClickListener;

    public void setOnItemClickListener(OnItemClickListener itemClickListener) {
        this.mItemClickListener = itemClickListener;
    }

    public void setOnLongClickListener(OnLongClickListener longClickListener) {
        this.mLongClickListener = longClickListener;
    }

    public interface OnItemClickListener {
        void OnItemClick(int position);
    }

    public interface OnLongClickListener {
        boolean onLongClick(int position);
    }

}

相關文章