Android如何优雅地实现ListView加载更多功能(1)
来源:互联网 发布:js uint8array 编辑:程序博客网 时间:2024/05/16 06:50
利用ListView的分类型Item功能实现加载更多功能
RecyclerView是Android5.0以后推出的新控件,相比于ListView可定制性更大,大有取代ListView之势。所以你可能会感觉,现在还谈ListView显得有点老套,技术有点out了。但是,不可否认的是,目前,使用ListView用来显示列表的还是占大部分的。所以,作为我日常之余,就抽空写了一个比较通用的ListView的框架。
下面这篇博客主要来实现ListView的上拉加载更多功能。可能也是公司项目开发里面,比较常用的技术实现!这个内容分两次更新,本篇博客将介绍ListView的Adapter的抽取过程。下一次会在本次的基础上,介绍加载更多功能的实现。
主要从以下方面讨论:
- 对BaseAdapter的四个抽象方法讲解
- 对getView方法的抽取
- 加载更多Item的添加
- 加载更多功能实现
后两部分内容的介绍麻烦查看Android如何优雅地实现ListView加载更多功能(2)
1、对BaseAdapter的四个抽象方法讲解
我们初学安卓时,就已经知道,写一个ListView的Adapter必须实现其以下四个方法,下面,我们先按照初学安卓时的写法先写一个适配器,算是对我们下面内容的一个导入:
public class AnzhiAdapter<T> extends BaseAdapter { private List<T> mList; private Context mContext; public AnzhiAdapter(Context context, List<T> list) { super(); this.mList = list; this.mContext = context; } @Override public int getCount() { return mList.size(); } @Override public T getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ holder = new ViewHolder(); holder.name = new TextView(mContext); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } //设置数据 //... return convertView; } static class ViewHolder { TextView name; }}
可以看到,我们每次写Adapter时,都需要实现这四个方法,然而,写法是如此的相似!重复代码是编程的中的大忌,我们要尽量避免写出重复代码,提高代码质量。再深入的讲,就涉及到代码重构这一高深莫测的学问了,我们不讲。有人说,程序员都很懒,从这就可以看出了,因为我们就连IDE自动生成了大部分的方法都不愿意去写,确实很懒,但是,我认为,这更是我们对精致生活的追求,代表了我们的一种生活态度,那就是不将就!扯远啦。回来再看!
接下来,我们可以对这个类进行一些必要的抽取,以简化我们日后编程的代码量。我们发现以下三个方法的写法,高度一致:
@Override public int getCount() { return mList.size(); } @Override public T getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; }
消灭重复代码,我们就从它们开始。所以,我们定义了一个泛型,在构造方法里面,添加了一个list参数用来传递ListView需要的数据集合,将这个list里面的元素的类型限制为T;然后,我们定义了一个成员变量mList来接收数据。所以,以上三个方法就实现完了,而且是一个通用的实现。接下来,我们重点讲解一下getView()这个方法。
2、对getView方法的抽取
我们刚刚开始接触安卓的时候,我们一般采用比较简单的写法,定义一个内部类ViewHolder。然后判断convertView是否为空,为空时,我们才去new一个ViewHolder的对象,不为空时,我们就直接复用convertView对象。这是相当于数学公式一般的写法,我们已经牢牢记住了,但是,这依然是一个高度重复的一个工作,程序员应该“懒”到连这丁点重复代码也不愿意写,还是前面的话,这是我们“不将就”的态度的体现。那么下面我们不妨接着这思路,进一步去想想,getView方法的重复代码,如何进一步进行抽取?
不妨先定义一个类,我们姑且就叫它为BaseHolder,当convertView为空时,我们以前需要去加载Item的布局文件,然后把这个viewHolder对象作为一个Tag设置给convertView进行标记保存。所以可以想到,我们可以将加载布局文件和设置Tag标记的这个过程,放在BaseHolder中完成,并且,只执行一次的过程,我们自然就放在构造器中完成。因为这是一个抽取出来的通用类,将来将给很多不同类型的Adapter提供Holder。所以将来的每一个Item的布局结构是未知的,这里不能去做具体实现。所以我们需要要写一个抽象方法,我们将方法名叫做initView(),有抽象方法了,这个BaseHolder类我们也必须加上abstract,变为一个抽象类。
当convertView不为空时,取出Tag标记强转为ViewHolder对象,这个没有办法进行进一步抽取。接下来就是设置数据的过程,因为Listview中每一个Item对应的数据类型都不一致,所在在父类中,是没法确定每一个条目的数据类型,所以定义一个泛型T,在BaseHolder中定义一个成员变量data,这个对象,将对Item做数据填充用。暴露这个对象的get、set方法作为赋值以及取值使用。当调用set方法为data赋值时,这时,data的数据就需要提供View展示出来,我们将方法名叫做initData(),这时因为前面说了Item的布局是不确定的,设置数据的过程,自然也是不能确定下来的,我们继续将此方法调用成一个抽象方法,让子类去实现。
接下来数据设置完成,按照以前的写法,就该返回convertView这个View了,那么我们在这里,需要返回的就是initView方法里面加载出来的View对象,我们不妨也把它定义成一个成员变量mItemView,暴露一个get方法getItemView(),用于返回这个对象。
以上是分析过程,需要养成习惯的是,需要操作界面的过程,我们都会用到上下文对象,所以,在构造方法中,我们需要添加一个上下文形参,用来接收上下文对象。
下面是BaseHolder的完整代码。
public abstract class BaseHolder<T> { public Context mContext; private View mItemView; private T data; public BaseHolder(Context context) { this.mContext = context; mItemView = initView(); mItemView.setTag(this); } public T getData() { return data; } /** * 设置Item的数据 * 因为Listview中每一个Item对应的数据类型都不一致,所在在父类中,是没法确定每一个条目的数据类型,所以定义一个泛型T * @param data */ public void setData(T data) { this.data = data; initData(); } /** * 返回Item的视图,用于填充ListView * @return */ public View getItemView() { return mItemView; } /** * 初始化每个Item的视图 * 每一个Item的布局结构是未知的,这里不能去做具体实现 * @return */ public abstract View initView(); /** * 填充Item的数据 * Item的布局是不确定的,设置数据的过程,自然也是不能确定下来的 */ public abstract void initData();}
上面我们有两个抽象方法,细心的你可能会发现,我把界面加载与数据填充分别抽取成了两个方法,其实这就是基于MVC编程的思想,将视图层与逻辑业务层分离编程。
接下来就是getView方法的书写。根据前面的分析,我们可以很轻松的写出。但是需要注意的是,因为在当前类中,我们还是无法确定Item的布局,所以,我又写了一个抽象方法getHolder(),让子类去帮忙实现。以下是具体代码。
@Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { itemHolder = getHolder(); } else { itemHolder = (BaseHolder) convertView.getTag(); } itemHolder.setData(getItem(position)); return itemHolder.getItemView(); }
下面,是AnzhiBaseAdapter的全部代码。
public abstract class AnzhiBaseAdapter<T> extends BaseAdapter { private List<T> mList; private Context mContext; private BaseHolder itemHolder; public AnzhiBaseAdapter(Context context, List<T> list) { super(); this.mList = list; this.mContext = context; } @Override public int getCount() { return mList.size(); } @Override public T getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { itemHolder = getHolder(); } else { itemHolder = (BaseHolder) convertView.getTag(); } itemHolder.setData(getItem(position)); return itemHolder.getItemView(); } public abstract BaseHolder getHolder() ;}
到现在,我们已经初步完成了对AnzhiBaseAdapter的编写,可以基于上面的代码,写一个例子来测试一下我们的抽取是否出现问题了。大致过程就是新建一个类例如叫MyAdapter继承自AnzhiBaseAdapter,实现getHolder方法,新建一个类MyTestHolder继承自BaseHolder,实现initView,和initData方法,然后在getHolder中返回MyTestHolder的对象。接下来在给ListView设置数据适配器时,设置成MyAdapter的对象即可。是不是非常简单呢?这我就不在这贴出来了,有兴趣的你可以自己写一个demo测试一下。
下一次更博,我将介绍,如何实现ListView的加载更多的功能,今天的内容,是一个基础。
- Android如何优雅地实现ListView加载更多功能(1)
- Android如何优雅地实现ListView加载更多功能(2)
- android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)
- android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)
- android ListView上拉加载更多 下拉刷新功能实现(采用pull-to-refresh)
- 使用AndroidAnnotations框架优雅地实现ListView功能例子
- apicloud如何实现优雅的下拉刷新与加载更多(Appcan也可类似实现)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- Android UI--自定义ListView(实现下拉刷新+加载更多)
- 实现Android ListView 自动加载更多内容
- Android ListView实现下拉刷新、加载更多
- android-----ListView上拉加载更多实现
- 蓝桥杯java第七届决赛第四题--路径之谜
- Cause: java.sql.SQLException: Access denied for user 'root1'@'localhost' (using password: YES)
- Eclipse开发软件中的各类问题总结
- Hello,My first blog!
- 预分配线程(prethreading)
- Android如何优雅地实现ListView加载更多功能(1)
- java 时间戳转化
- java多线程—cpu缓存
- 5.21吴老师上课总结
- 入坑与爬坑----Android系列
- spring boot 理解
- Spring——注解
- 利用POI框架的SAX方式处理大数据2007版Excel(xlsx)
- NodeJs 安装