构建一个可复用的自定义BaseAdapter

简介: 本节给大家带来的是构建一个可复用的自定义BaseAdapter,我们每每涉及到ListView GridView等其他的Adapter控件,都需要自己另外写一个BaseAdapter类,这样显得非常麻烦, 又比如,我们想在一个界面显示两个ListView的话,我们也是需要些两个BaseAdapter。

本节给大家带来的是构建一个可复用的自定义BaseAdapter,我们每每涉及到ListView GridView等其他的Adapter控件,都需要自己另外写一个BaseAdapter类,这样显得非常麻烦, 又比如,我们想在一个界面显示两个ListView的话,我们也是需要些两个BaseAdapter。

1.我们一点点开始改:

首先我们把上节写的自定义BaseAdapter贴下,等下我们就要对他进行升级改造

/**
 * Created by Jay on 2015/9/21 0021.
 */
public class MyAdapter extends BaseAdapter {
    private Context mContext;
    private LinkedList<Data> mData;
    public MyAdapter() {
    }
    public MyAdapter(LinkedList<Data> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }
    @Override
    public int getCount() {
        return mData.size();
    }
    @Override
    public Object getItem(int position) {
        return null;
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent());
        return convertView;
    }
    //添加一个元素
    public void add(Data data) {
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }
    //往特定位置,添加一个元素
    public void add(int position,Data data){
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }
    public void remove(Data data) {
        if(mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }
    public void remove(int position) {
        if(mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }
    public void clear() {
        if(mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }
    private class ViewHolder {
        ImageView img_icon;
        TextView txt_content;
    }
}

升级1:将Entity设置成泛型

好的,毕竟我们传递过来的Entitiy实体类可能千奇百怪,比如有Person,Book,Wether等,所以我们 将Entity设置成泛型,修改后的代码如下:

public class MyAdapter<T> extends BaseAdapter {
    private Context mContext;
    private LinkedList<T> mData;
    public MyAdapter() {
    }
    public MyAdapter(LinkedList<T> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }
    @Override
    public int getCount() {
        return mData.size();
    }
    @Override
    public Object getItem(int position) {
        return null;
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent());
        return convertView;
    }
    //添加一个元素
    public void add(T data) {
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }
    //往特定位置,添加一个元素
    public void add(int position,T data){
        if (mData == null) {
            mData = new LinkedList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }
    public void remove(T data) {
        if(mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }
    public void remove(int position) {
        if(mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }
    public void clear() {
        if(mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }
    private class ViewHolder {
        ImageView img_icon;
        TextView txt_content;
    }
}

好的,上面我们做的事仅仅是将Data类型换成了泛型T!

升级2:ViewHolder类的升级改造:

我们先来看看前面我们的ViewHolder干了什么? 答:findViewById,设置控件状态; 下面我们想在完成这个基础上,将getView()方法大部分的逻辑写到ViewHolder类里, 这个ViewHolder要做的事:

  • 定义一个查找控件的方法,我们的思路是通过暴露公共的方法,调用方法时传递过来 控件id,以及设置的内容,比如TextView设置文本: public ViewHolder setText(int id, CharSequence text){文本设置}
  • 将convertView复用部分搬到这里,那就需要传递一个context对象了,我们把需要获取 的部分都写到构造方法中!
  • 写一堆设置方法(public),比如设置文字大小颜色,图片背景等!

好的,接下来我们就来一步步改造我们的ViewHolder类

1)相关参数与构造方法:

public static class ViewHolder {
    private SparseArray<View> mViews;   //存储ListView 的 item中的View
    private View item;                  //存放convertView
    private int position;               //游标
    private Context context;            //Context上下文
    //构造方法,完成相关初始化
    private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
        mViews = new SparseArray<>();
        this.context = context;
        View convertView = LayoutInflater.from(context).inflate(layoutRes, parent,false);
        convertView.setTag(this);
        item = convertView;
    }
    ImageView img_icon;
    TextView txt_content;
}

2)绑定ViewHolder与Item

在上面的基础上我们再添加一个绑定的方法

//绑定ViewHolder与item
public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                              int layoutRes, int position) {
    ViewHolder holder;
    if(convertView == null) {
        holder = new ViewHolder(context, parent, layoutRes);
    } else {
        holder = (ViewHolder) convertView.getTag();
        holder.item = convertView;
    }
    holder.position = position;
    return holder;
}

3)根据id获取集合中保存的控件

public <T extends View> T getView(int id) {
    T t = (T) mViews.get(id);
    if(t == null) {
        t = (T) item.findViewById(id);
        mViews.put(id, t);
    }
    return t;
}

4) 接着我们再定义一堆暴露出来的方法

/**
 * 获取当前条目
 */
public View getItemView() {
    return item;
}
/**
 * 获取条目位置
 */
public int getItemPosition() {
    return position;
}
/**
 * 设置文字
 */
public ViewHolder setText(int id, CharSequence text) {
    View view = getView(id);
    if(view instanceof TextView) {
        ((TextView) view).setText(text);
    }
    return this;
}
/**
 * 设置图片
 */
public ViewHolder setImageResource(int id, int drawableRes) {
    View view = getView(id);
    if(view instanceof ImageView) {
        ((ImageView) view).setImageResource(drawableRes);
    } else {
        view.setBackgroundResource(drawableRes);
    }
    return this;
}
/**
 * 设置点击监听
 */
public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
    getView(id).setOnClickListener(listener);
    return this;
}
/**
 * 设置可见
 */
public ViewHolder setVisibility(int id, int visible) {
    getView(id).setVisibility(visible);
    return this;
}
/**
 * 设置标签
 */
public ViewHolder setTag(int id, Object obj) {
    getView(id).setTag(obj);
    return this;
}
//其他方法可自行扩展

升级3:定义一个抽象方法,完成ViewHolder与Data数据集的绑定

public abstract void bindView(ViewHolder holder, T obj);

我们创建新的BaseAdapter的时候,实现这个方法就好,另外,别忘了把我们自定义 的BaseAdapter改成abstact抽象的!

升级4:修改getView()部分的内容

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
            , position);
    bindView(holder,getItem(position));
    return holder.getItemView();
}

2.升级完毕,我们写代码来体验下:

我们要实现的效果图:

网络异常,图片无法展示
|

就是上面有两个列表,布局不一样,但是我只使用一个BaseAdapter类来完成上述效果!

关键代码如下:

MainActivity.java

public class MainActivity extends AppCompatActivity {
private Context mContext;
private ListView list_book;
private ListView list_app;
private MyAdapter<App> myAdapter1 = null;
private MyAdapter<Book> myAdapter2 = null;
private List<App> mData1 = null;
private List<Book> mData2 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mContext = MainActivity.this;
    init();
}
private void init() {
    list_book = (ListView) findViewById(R.id.list_book);
    list_app = (ListView) findViewById(R.id.list_app);
    //数据初始化
    mData1 = new ArrayList<App>();
    mData1.add(new App(R.mipmap.iv_icon_baidu,"百度"));
    mData1.add(new App(R.mipmap.iv_icon_douban,"豆瓣"));
    mData1.add(new App(R.mipmap.iv_icon_zhifubao,"支付宝"));
    mData2 = new ArrayList<Book>();
    mData2.add(new Book("《第一行代码Android》","郭霖"));
    mData2.add(new Book("《Android群英传》","徐宜生"));
    mData2.add(new Book("《Android开发艺术探索》","任玉刚"));
    //Adapter初始化
    myAdapter1 = new MyAdapter<App>((ArrayList)mData1,R.layout.item_one) {
        @Override
        public void bindView(ViewHolder holder, App obj) {
            holder.setImageResource(R.id.img_icon,obj.getaIcon());
            holder.setText(R.id.txt_aname,obj.getaName());
        }
    };
    myAdapter2 = new MyAdapter<Book>((ArrayList)mData2,R.layout.item_two) {
        @Override
        public void bindView(ViewHolder holder, Book obj) {
            holder.setText(R.id.txt_bname,obj.getbName());
            holder.setText(R.id.txt_bauthor,obj.getbAuthor());
        }
    };
    //ListView设置下Adapter:
    list_book.setAdapter(myAdapter2);
    list_app.setAdapter(myAdapter1);
}

我们写的可复用的BaseAdapter的使用就如上面所述。

3.代码示例下载:

ListViewDemo4.zip

贴下最后写好的MyAdapter类吧,可根据自己的需求进行扩展:

MyAdapter.java

/**
 * Created by Jay on 2015/9/22 0022.
 */
public abstract class MyAdapter<T> extends BaseAdapter {
    private ArrayList<T> mData;
    private int mLayoutRes;           //布局id
    public MyAdapter() {
    }
    public MyAdapter(ArrayList<T> mData, int mLayoutRes) {
        this.mData = mData;
        this.mLayoutRes = mLayoutRes;
    }
    @Override
    public int getCount() {
        return mData != null ? mData.size() : 0;
    }
    @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) {
        ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
                , position);
        bindView(holder, getItem(position));
        return holder.getItemView();
    }
    public abstract void bindView(ViewHolder holder, T obj);
    //添加一个元素
    public void add(T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }
    //往特定位置,添加一个元素
    public void add(int position, T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }
    public void remove(T data) {
        if (mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }
    public void remove(int position) {
        if (mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }
    public void clear() {
        if (mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }
    public static class ViewHolder {
        private SparseArray<View> mViews;   //存储ListView 的 item中的View
        private View item;                  //存放convertView
        private int position;               //游标
        private Context context;            //Context上下文
        //构造方法,完成相关初始化
        private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
            mViews = new SparseArray<>();
            this.context = context;
            View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false);
            convertView.setTag(this);
            item = convertView;
        }
        //绑定ViewHolder与item
        public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                                      int layoutRes, int position) {
            ViewHolder holder;
            if (convertView == null) {
                holder = new ViewHolder(context, parent, layoutRes);
            } else {
                holder = (ViewHolder) convertView.getTag();
                holder.item = convertView;
            }
            holder.position = position;
            return holder;
        }
        @SuppressWarnings("unchecked")
        public <T extends View> T getView(int id) {
            T t = (T) mViews.get(id);
            if (t == null) {
                t = (T) item.findViewById(id);
                mViews.put(id, t);
            }
            return t;
        }
        /**
         * 获取当前条目
         */
        public View getItemView() {
            return item;
        }
        /**
         * 获取条目位置
         */
        public int getItemPosition() {
            return position;
        }
        /**
         * 设置文字
         */
        public ViewHolder setText(int id, CharSequence text) {
            View view = getView(id);
            if (view instanceof TextView) {
                ((TextView) view).setText(text);
            }
            return this;
        }
        /**
         * 设置图片
         */
        public ViewHolder setImageResource(int id, int drawableRes) {
            View view = getView(id);
            if (view instanceof ImageView) {
                ((ImageView) view).setImageResource(drawableRes);
            } else {
                view.setBackgroundResource(drawableRes);
            }
            return this;
        }
        /**
         * 设置点击监听
         */
        public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
            getView(id).setOnClickListener(listener);
            return this;
        }
        /**
         * 设置可见
         */
        public ViewHolder setVisibility(int id, int visible) {
            getView(id).setVisibility(visible);
            return this;
        }
        /**
         * 设置标签
         */
        public ViewHolder setTag(int id, Object obj) {
            getView(id).setTag(obj);
            return this;
        }
        //其他方法可自行扩展
    }
}
相关文章
|
12月前
|
编译器
(9)Qt中信号与槽重载的解决方案
本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。
513 3
|
SQL 缓存 安全
Android ORM 框架之 greenDAO
Android ORM 框架之 greenDAO
791 0
|
11月前
|
JavaScript 搜索推荐 前端开发
DevDocs具备**一站式搜索、多语言支持、离线访问等**特色功能。
DevDocs具备**一站式搜索、多语言支持、离线访问等**特色功能。
214 56
|
12月前
|
算法 决策智能
基于禁忌搜索算法的VRP问题求解matlab仿真,带GUI界面,可设置参数
该程序基于禁忌搜索算法求解车辆路径问题(VRP),使用MATLAB2022a版本实现,并带有GUI界面。用户可通过界面设置参数并查看结果。禁忌搜索算法通过迭代改进当前解,并利用记忆机制避免陷入局部最优。程序包含初始化、定义邻域结构、设置禁忌列表等步骤,最终输出最优路径和相关数据图表。
|
11月前
|
机器学习/深度学习 人工智能 自然语言处理
Tokenformer:基于参数标记化的高效可扩展Transformer架构
本文是对发表于arXiv的论文 "TOKENFORMER: RETHINKING TRANSFORMER SCALING WITH TOKENIZED MODEL PARAMETERS" 的深入解读与扩展分析。主要探讨了一种革新性的Transformer架构设计方案,该方案通过参数标记化实现了模型的高效扩展和计算优化。
548 0
|
人工智能 运维 Kubernetes
拥抱智算时代:阿里云容器服务智能、托管、弹性新体验
在2024云栖大会容器计算专场,给大家分享容器服务的新产品体验,本次分享,我们聚焦容器服务是如何通过智能、托管、弹性的产品新体验,来助力客户拥抱智算时代的。
|
自然语言处理 安全 网络安全
WBCE CMS v1.5.2 远程命令执行(CVE-2022-25099)
WBCE CMS v1.5.2 远程命令执行(CVE-2022-25099)
|
存储 关系型数据库 MySQL
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT *、分页查询的优化、合理使用连接、子查询的优化)(上)
2093 0
|
XML Java Android开发
Android Studio App开发之列表类视图中基本适配器BaseAdapter的使用及实战(附源码 超详细)
Android Studio App开发之列表类视图中基本适配器BaseAdapter的使用及实战(附源码 超详细)
387 0
【Qt 学习笔记】Qt的坐标体系
【Qt 学习笔记】Qt的坐标体系
439 0