美文网首页各种view精选案例Android进阶之路
Android通用的Adapter,或许你用我这一个就够了

Android通用的Adapter,或许你用我这一个就够了

作者: 刘付文 | 来源:发表于2018-03-20 17:24 被阅读716次
    一、概述

    相信Android开发,特别是电商项目开发,使用RecyclerView、ListView、GridView是正常不过的了。一个项目下来,基本就是一直在写Adapter。刚开始写Adapter觉得没什么,无非就是ListView的继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式;RecyclerView的就继承 RecyclerView.Adapter,复写onCreateViewHolder、onBindViewHolder然后实现便完事。但当我写到10遍、100遍甚至更多的时候,我就不想写了,反正都是这种写法,也没什么新的套路。于是我就想写一个RecyclerView、ListView、GridView通用的Adapter。

    二、常见ListView、RecyclerView Adapter写法的例子

    代码没什么难度可以随便看看就好。

    public class ListViewAdapter extends BaseAdapter  
    {  
        private LayoutInflater mInflater;  
        private Context mContext;  
        private List<String> mDatas;  
        private int mLayoutId;
      
        public ListViewAdapter(Context context, List<String> mDatas,int layoutId)  
        {  
            mInflater = LayoutInflater.from(context);  
            this.mContext = context;  
            this.mDatas = mDatas;  
            this.mLayoutId = layoutId;
        }  
      
        @Override  
        public int getCount()  
        {  
            return mDatas.size();  
        }  
      
        @Override  
        public Object getItem(int position)  
        {  
            return mDatas.get(position);  
        }  
      
        @Override  
        public long getItemId(int position)  
        {  
            return position;  
        }  
      
        @Override  
        public View getView(int position, View convertView, ViewGroup parent)  
        {  
            ViewHolder viewHolder = null;  
            if (convertView == null)  
            {  
                convertView = mInflater.inflate(R.mLayoutId, parent, false);  
                viewHolder = new ViewHolder();  
                viewHolder.mTextView = (TextView) convertView  
                        .findViewById(R.id.id_tv);  
                convertView.setTag(viewHolder);  
            } else  
            {  
                viewHolder = (ViewHolder) convertView.getTag();  
            }  
            viewHolder.mTextView.setText(mDatas.get(position));  
            return convertView;  
        }  
      
        private final class ViewHolder  
        {  
            TextView mTextView;  
        }  
      
    }  
    
    private class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.Holder> {
    
        private LayoutInflater mInflater;
        private Context mContext;
        private List<String> mData;
        private int mLayoutId;
    
        public RecyclerAdapter(Context context, List<String> data, int layoutId) {
            mInflater = LayoutInflater.from(context);
            this.mContext = context;
            this.mData = data;
            this.mLayoutId = layoutId;
        }
    
        @Override
        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = mInflater.inflate(mLayoutId, parent, false);
            return new Holder(view);
        }
    
        @Override
        public void onBindViewHolder(Holder holder, int position) {
            holder.tv.setText(mData.get(position));
        }
    
        @Override
        public int getItemCount() {
            return mData.size();
        }
    
        class Holder extends RecyclerView.ViewHolder {
            public TextView tv;
    
            public Holder(View itemView) {
                super(itemView);
                tv = itemView.findViewById(R.id.tv);
            }
        }
    }
    
    三、ListView、RecyclerView Adapter一些共性分析
    1. 要显示的条目个数
    2. 要显示和条目对应的类型
    3. ListView、RecyclerView中,总共有多少个条目类型
    4. 根据不同的条目类型加载不同的View
    5. ListView复用条目convertView,RecyclerView自带ViewHoler复用
    
    四、抽取RecyclerView、ListView、GridView适配器的基类

    由于要通用RecyclerView、ListView、GridView只能将RecyclerView.Adapter和ListAdapter,SpinnerAdapter
    这些都给实现了。里面也没多少个方法,其实也是很简单。至于一些方法的实现我考贝BaseAdapter的实现,
    大家可以去看看BaseAdapter的源码。

    public class BaseAdapter extends RecyclerView.Adapter implements ListAdapter, SpinnerAdapter {
        private final DataSetObservable mDataSetObservable = new DataSetObservable();
    
        // RecyclerView========================================================================
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return null;
        }
    
        // RecyclerView
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    
        }
    
        // RecyclerView
        @Override
        public int getItemCount() {
            return 0;
        }
        // RecyclerView========================================================================
    
        // ListView========================================================================
        @Override
        public boolean areAllItemsEnabled() {
            return true;
        }
    
        @Override
        public boolean isEnabled(int position) {
            return true;
        }
    
        @Override
        public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }
    
        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.unregisterObserver(observer);
        }
    
        public void notifyListDataSetChanged() {
            mDataSetObservable.notifyChanged();
        }
    
    
        @Override
        public Object getItem(int position) {
            return null;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return null;
        }
    
        @Override
        public int getViewTypeCount() {
            return 1;
        }
    
        @Override
        public int getItemViewType(int position) {
            return 0;
        }
    
        @Override
        public int getCount() {
            return 0;
        }
        
        @Override
        public boolean isEmpty() {
            return getCount() == 0;
        }
    
        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            return getView(position, convertView, parent);
        }
    }
    
    五、抽取支持ListView、 GridView、 RecyclerView多条目的共性
    public interface QuickMultiSupport<T> {
        /**
         * 获取多条目View类型的数量
         */
        int getViewTypeCount();
    
        /**
         * 根据数据,获取多条目布局ID
         */
        int getLayoutId(T data);
    
        /**
         * 根据数据,获取多条目的ItemViewType
         */
        int getItemViewType(T data);
    
    
        /**
         * 是否合并条目-->>使用RecyclerView时,如果无效,请用原生的RecyclerView
         */
        boolean isSpan(T data);
    
    六、打造RecyclerView、ListView、GridView通用的适配器

    由于要同时适配RecyclerView、ListView、GridView,也就等于把两个Adapter的实现放在一个类里面
    所以代码有点多,但代码我已分开,很容易看。
    还有数据都复制出来的,条目的增删改查都在Adapter里面。

    /**
     * RecyclerView、ListView、GridView通用的适配器
     */
    public abstract class QuickAdapter<T> extends BaseAdapter {
        private Context mContext;
        private List<T> mData;
        private int mLayoutId;
        private QuickMultiSupport<T> mSupport;
        private boolean isRecycler;
        private int mPosition;
    
        public QuickAdapter(Context context, List<T> data, int layoutId) {
            this.mContext = context;
            this.mData = data == null ? new ArrayList<T>() : new ArrayList<T>(data);
            this.mLayoutId = layoutId;
        }
    
        public QuickAdapter(Context context, List<T> data, QuickMultiSupport<T> support) {
            this(context, data, 0);
            this.mSupport = support;
        }
    
        @Override
        public int getCount() {
            return mData.size();
        }
    
        @Override
        public T getItem(int position) {
            return mData.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            QuickViewHolder holder;
            if (convertView == null) {
                int layoutId = mLayoutId;
                // 多条目的
                if (mSupport != null) {
                    layoutId = mSupport.getLayoutId(mData.get(position));
                }
                // 创建ViewHolder
                holder = createListHolder(parent, layoutId);
            } else {
                holder = (QuickViewHolder) convertView.getTag();
                // 防止失误,还要判断
                if (mSupport != null) {
                    int layoutId = mSupport.getLayoutId(mData.get(position));
                    // 如果布局ID不一样,又重新创建
                    if (layoutId != holder.getLayoutId()) {
                        // 创建ViewHolder
                        holder = createListHolder(parent, layoutId);
                    }
                }
    
            }
            // 绑定View的数据
            convert(holder, mData.get(position), position);
            return holder.itemView;
        }
    
        /**
         * 创建ListView的Holer
         */
        @NonNull
        private QuickViewHolder createListHolder(ViewGroup parent, int layoutId) {
            QuickViewHolder holder;
            View itemView = LayoutInflater.from(mContext).inflate(layoutId, parent, false);
            holder = new QuickViewHolder(itemView, layoutId);
            itemView.setTag(holder);
            return holder;
        }
    
        /**
         * ViewType的数量
         */
        @Override
        public int getViewTypeCount() {
            // 多条目的
            if (mSupport != null) {
                return mSupport.getViewTypeCount() + super.getViewTypeCount();
            }
            return super.getViewTypeCount();
        }
    
        /**
         * 这个方法是共用的
         */
        @Override
        public int getItemViewType(int position) {
            mPosition = position;
            // 多条目的
            if (mSupport != null) {
                return mSupport.getItemViewType(mData.get(position));
            }
            return super.getItemViewType(position);
        }
    
    
        // RecyclerView=================================================================================
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            isRecycler = true;
            // 如果是多条目,viewType就是布局ID
            View view;
            if (mSupport != null) {
                int layoutId = mSupport.getLayoutId(mData.get(mPosition));
                view = LayoutInflater.from(mContext).inflate(layoutId, parent, false);
            } else {
                view = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false);
            }
    
            QuickViewHolder holder = new QuickViewHolder(view);
            return holder;
        }
    
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof QuickViewHolder) {
                convert((QuickViewHolder) holder, mData.get(position), position);
            }
    
        }
    
        @Override
        public int getItemCount() {
            return mData.size();
        }
    
        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            if (mSupport == null || recyclerView == null) {
                return;
            }
            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager) {
                final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
                final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
                // 如果设置合并单元格就占用SpanCount那个多个位置
                gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        if (mSupport.isSpan(mData.get(position))) {
                            return gridLayoutManager.getSpanCount();
                        } else if (spanSizeLookup != null) {
                            return spanSizeLookup.getSpanSize(position);
                        }
                        return 1;
                    }
                });
                gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
            }
        }
    
        @Override
        public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
            if (mSupport == null) {
                return;
            }
            int position = holder.getLayoutPosition();
            // 如果设置合并单元格
            if (mSupport.isSpan(mData.get(position))) {
                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
                if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
                    StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                    p.setFullSpan(true);
                }
            }
        }
    
        // RecyclerView=================================================================================
    
    
        /**
         * 绑定View的数据
         */
        protected abstract void convert(QuickViewHolder holder, T item, int position);
    
    
        //==========================================数据相关================================================
        public void add(T elem) {
            mData.add(elem);
            notifyData();
    
        }
        public void addAll(List<T> data) {
            mData.addAll(data);
            notifyData();
        }
        
        public void addFirst(T elem) {
            mData.add(0, elem);
            notifyData();
        }
        
        public void set(T oldElem, T newElem) {
            set(mData.indexOf(oldElem), newElem);
            notifyData();
        }
        
        public void set(int index, T elem) {
            mData.set(index, elem);
            notify();
        }
    
        public void remove(T elem) {
            mData.remove(elem);
            notifyData();
        }
    
        public void remove(int index) {
            mData.remove(index);
            notifyData();
        }
    
        public void replaceAll(List<T> elem) {
            mData.clear();
            mData.addAll(elem);
            notifyData();
        }
    
        /**
         * 清除
         */
        public void clear() {
            mData.clear();
            notifyData();
        }
    
        private void notifyData() {
            if (isRecycler) {
                notifyDataSetChanged();
            } else {
                notifyListDataSetChanged();
            }
        }
    
        public List<T> getData() {
            return mData;
        }
    }
    
    七、通用ViewHolder的抽取

    ViewHolder最主要就是实现平时常用的方法,比如:点击事件、长按事件、给TextView设置内容等等
    如果不够,实际开发可以自己添加。

    public class QuickViewHolder extends RecyclerView.ViewHolder {
        private SparseArray<WeakReference<View>> mViews;
        private int mLayoutId;
    
        public QuickViewHolder(View itemView) {
            this(itemView, -1);
        }
    
        public QuickViewHolder(View itemView, int layoutId) {
            super(itemView);
            mViews = new SparseArray<>();
            this.mLayoutId = layoutId;
    
        }
    
        public int getLayoutId() {
            return mLayoutId;
        }
    
        /**
         * 设置条目的点击事件
         */
        public QuickViewHolder setOnClickListener(View.OnClickListener listener) {
            itemView.setOnClickListener(listener);
            return this;
        }
    
        /**
         * 设置条目的长按事件
         */
        public QuickViewHolder setOnLongClickListener(View.OnLongClickListener listener) {
            itemView.setOnLongClickListener(listener);
            return this;
        }
    
        /**
         * 设置View的点击事件
         *
         * @return
         */
        public QuickViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
            View view = getView(viewId);
            if (view != null) {
                view.setOnClickListener(listener);
            }
            return this;
        }
    
        /**
         * 获取条目的View
         */
        public View getView() {
            return itemView;
        }
    
        /**
         * 根据ID获取条目里面的View
         */
        public <T extends View> T getView(int viewId) {
            WeakReference<View> viewWeakReference = mViews.get(viewId);
            View view = null;
            if (viewWeakReference == null) {
                view = itemView.findViewById(viewId);
                if (view != null) {
                    mViews.put(viewId, new WeakReference<>(view));
                }
            } else {
                view = viewWeakReference.get();
            }
            return (T) view;
        }
    
        public QuickViewHolder setText(int viewId, CharSequence text) {
            TextView tv = getView(viewId);
            if (tv != null && !TextUtils.isEmpty(text)) {
                tv.setText(text);
            }
            return this;
        }
    
        /**
         * 设置图片背景颜色
         */
        public QuickViewHolder setTextColor(int viewId, int color) {
            TextView view = getView(viewId);
            if (view != null) {
                view.setTextColor(color);
            }
            return this;
        }
    
        /**
         * 设置控件是否可见
         */
        public QuickViewHolder setVisible(int viewId, int visible) {
            View view = getView(viewId);
            view.setVisibility(visible);
            return this;
        }
    
        /**
         * 设置控件选中
         */
        public QuickViewHolder setChecked(int viewId, boolean checked) {
            Checkable view = getView(viewId);
            view.setChecked(checked);
            return this;
        }
    
        /**
         * 设置控件背景
         */
        public QuickViewHolder setBackgroundRes(int viewId, int backgroundRes) {
            View view = getView(viewId);
            view.setBackgroundResource(backgroundRes);
            return this;
        }
    
        /**
         * 设置图片
         */
        public QuickViewHolder setImageResource(int viewId, int imageResId) {
            ImageView imageView = getView(viewId);
            imageView.setImageResource(imageResId);
            return this;
        }
    
        /**
         * 设置图片
         */
        public QuickViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
            ImageView imageView = getView(viewId);
            imageView.setImageBitmap(bitmap);
            return this;
        }
    
    
    }
    
    八、项目实际使用

    我只写了多条目的测试使用,对于一种类型的写法更为简单,我就不写了。

    public class MainActivity extends AppCompatActivity {
    
        private List<IViewType> mData = new ArrayList<>();
        private QuickMultiSupport<IViewType> mQuickSupport;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initData();
            initViews();
        }
    
        /**
         * 多条目的ViewType
         */
    
        public interface IViewType {
            int getItemViewType();
        }
    
        private void initData() {
            for (int i = 0; i < 199; i++) {
                if (i % 10 == 0) {
                    MultiBean bean = new MultiBean();
                    bean.name = "mData--------" + i;
                    mData.add(bean);
                } else {
                    MultiBean1 bean = new MultiBean1();
                    bean.name = "mData--------" + i;
                    mData.add(bean);
                }
            }
            // 多条目支持
            mQuickSupport = new QuickMultiSupport<IViewType>() {
                // 条目总共两种类型
                @Override
                public int getViewTypeCount() {
                    return 2;
                }
    
                // 根据不用的JavaBean返回不同的布局
                @Override
                public int getLayoutId(IViewType data) {
                    if (data instanceof MultiBean) {
                        return R.layout.item_list1;
                    }
                    return R.layout.item_list;
                }
    
                @Override
                public int getItemViewType(IViewType data) {
                    return data.getItemViewType();
                }
    
                @Override
                public boolean isSpan(IViewType data) {
                    // 是否占用一个条目,针对RecyclerView
                    if (data instanceof MultiBean) {
                        return true;
                    }
                    return false;
                }
            };
        }
    
        private void initViews() {
            ListView listView = findViewById(R.id.list_view);
            RecyclerView recyclerView = findViewById(R.id.recycler_view);
            // ListView设置Adapter
            listView.setAdapter(new CommAdapter(this, mData, mQuickSupport));
            // RecyclerView设置Adapter
            recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
            recyclerView.setAdapter(new CommAdapter(this, mData, mQuickSupport));
        }
    
        class CommAdapter extends QuickAdapter<IViewType> {
            public CommAdapter(Context context, List<IViewType> data, int layoutId) {
                super(context, data, layoutId);
            }
    
            public CommAdapter(Context context, List<IViewType> data, QuickMultiSupport<IViewType> support) {
                super(context, data, support);
            }
    
            @Override
            protected void convert(QuickViewHolder holder, IViewType item, final int position) {
                holder.setText(R.id.tv, item.toString());
                holder.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // 点击移除当前条目
                        remove(position);
                    }
                });
            }
        }
    }
    

    至此无论是RecyclerView还是ListView终于只用一个Adapter,是不是很开心
    项目运行的实际效果:左边是ListView,右边是RecyclerView。


    实际效果.jpg
    九、感谢

    鸿洋大神的
    1.Android 快速开发系列 打造万能的ListView GridView 适配器
    2.为RecyclerView打造通用Adapter 让RecyclerView更加好用

    相关文章

      网友评论

      • 树叶秋:onCreateViewHolder这个方法的执行时机有些问题?isrecycler这个条件不会先执行,导致执行了listview的notify方法,显示不出来布局
      • 30d510f59682:addHead,addFoot可以吗?
        刘付文:@cbbs Head和Foot就是多条目的一种而已
      • Cliper:有空一起打撸,我也很菜
      • AWeiLoveAndroid:写得很用心 点个赞支持一下:+1:

      本文标题:Android通用的Adapter,或许你用我这一个就够了

      本文链接:https://www.haomeiwen.com/subject/zisbqftx.html