ListView之GeneralAdapter
2016-04-15 22:42
211 查看
1、前言:
ListView的Adapter相信Android的小伙伴都非常的熟悉了,有很多人还会有一些很好的办法,看了很多优秀的这方面的文章,自己也有了一些自己的看法,这些想法多了,就会如梗在喉,不吐不快。
2、概述
ListView是我们项目中最为常用的控件之一,它很好的贯彻了Java的一个类只做一件事的面向对象编程的思想,同时很好的诠释了JavaEE MVC编程思想,从这个方向理解,ListView就是MVC的V了,Adapter就是C,M嘛,就是我们的数据模型,至于是什么样的数据 ,就要看我们的业务逻辑了。
3、传统写法:
我们知道,ListView要用到Adapter,ArrartAdapter与SimpleAdapter的使用网上有很多例子,基本思想都差不多,随便拿来改改就能用,这里不多做介绍。一般我们用的最多的就是自定义的Adapter,继承自BaseAdapter,这里就从这个地方谈起。
BaseAdapter是一个Abstract类,这有三个方法必须复写,别是public int getCount(),public Object getItem(int position),public long getItemId(int position),public View getView(int position,
View convertView, ViewGroup parent);
(1)没有优化的例子:
(2)优化的例子:
4、进一步思考:
上面的代码的确可以使用,并且也是Google推荐的做法,也是很容易理解的代码,但是写多了,就会觉得代码量很大,且很多都 是一样的代码,这不符合程序员的一惯的懒惰的优良作风。那上面的代码又有什么问题呢?最起码有下面的几个问题:
(1)Context在这里起的作用是必须的吗?
(2)传进去的数据只能是String类型(写死的)
那怎么来解决这些问题呢?请看下面的例子:
当然上面的代码只是一个简单的抽象和抽取,其实ListView还有很多可以优化的地方,比如,就像ListView与Adapter之间的观察者模式,其实我们可以做成让Adapter再做一回观察者,数据源做被观察者,这样就可以实现只要数据变化了,ListView就会自动更新,下一篇将实现上述能够自动更新的ListView
本文资源下载:点击打开链接:http://download.csdn.net/detail/xinxincement/9492966
ListView的Adapter相信Android的小伙伴都非常的熟悉了,有很多人还会有一些很好的办法,看了很多优秀的这方面的文章,自己也有了一些自己的看法,这些想法多了,就会如梗在喉,不吐不快。
2、概述
ListView是我们项目中最为常用的控件之一,它很好的贯彻了Java的一个类只做一件事的面向对象编程的思想,同时很好的诠释了JavaEE MVC编程思想,从这个方向理解,ListView就是MVC的V了,Adapter就是C,M嘛,就是我们的数据模型,至于是什么样的数据 ,就要看我们的业务逻辑了。
3、传统写法:
我们知道,ListView要用到Adapter,ArrartAdapter与SimpleAdapter的使用网上有很多例子,基本思想都差不多,随便拿来改改就能用,这里不多做介绍。一般我们用的最多的就是自定义的Adapter,继承自BaseAdapter,这里就从这个地方谈起。
BaseAdapter是一个Abstract类,这有三个方法必须复写,别是public int getCount(),public Object getItem(int position),public long getItemId(int position),public View getView(int position,
View convertView, ViewGroup parent);
(1)没有优化的例子:
public class MyAdapter extends BaseAdapter{ private Context mContext; private List<String> mDatas; private int mItemLayoutid; public MyAdapter(Context mContext, List<String> mDatas, int mItemLayoutid) { super(); this.mContext = mContext; this.mDatas = mDatas; this.mItemLayoutid = mItemLayoutid; } @Override public int getCount() { // TODO 自动生成的方法存根 return mDatas.size(); } @Override public Object getItem(int position) { // TODO 自动生成的方法存根 return mDatas.get(position); } @Override public long getItemId(int position) { // TODO 自动生成的方法存根 return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = LayoutInflater.from(mContext).inflate(mItemLayoutid, parent,false); TextView textview = (TextView) convertView.findViewById(R.id.item_textview); textview.setText(mDatas.get(position)); return convertView; } }以上代码在getView中每次调用都会从xml资源中去加载一个view,并找出里面的控件,然后给这个控件进行赋值,这样的写法是可以运行的,如果数据量小的话,也没有什么问题,但是google官方给出更好的实现:
(2)优化的例子:
public class MyAdapter extends BaseAdapter{ private Context mContext; private List<String> mDatas; private int mItemLayoutid; public MyAdapter(Context mContext, List<String> mDatas, int mItemLayoutid) { super(); this.mContext = mContext; this.mDatas = mDatas; this.mItemLayoutid = mItemLayoutid; } @Override public int getCount() { // TODO 自动生成的方法存根 return mDatas.size(); } @Override public Object getItem(int position) { // TODO 自动生成的方法存根 return mDatas.get(position); } @Override public long getItemId(int position) { // TODO 自动生成的方法存根 return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewholder = null; if(convertView == null){ viewholder = new ViewHolder(); convertView = LayoutInflater.from(mContext).inflate(mItemLayoutid, parent,false); viewholder.mItemContent = (TextView) convertView.findViewById(R.id.item_textview); convertView.setTag(viewholder); }else{ convertView = (View) convertView.getTag(); } viewholder.mItemContent.setText(mDatas.get(position)); return convertView; } class ViewHolder{ private TextView mItemContent; } }以上的代码中,用一个ViewHolder类来承载了你用xml写的view,注意我用了承载这个词,因为我找不到更好的词可以在这个地方拿来用,反正基本意思就是这个ViewHolder代表了你的View,其实在内存里,这个ViewHolder中的字段指向的和View是同一块内存,所以我们给Viewholder的实例赋值,也就是给你要返回的View中的字段(或属性)赋值,其本质是一样的。
4、进一步思考:
上面的代码的确可以使用,并且也是Google推荐的做法,也是很容易理解的代码,但是写多了,就会觉得代码量很大,且很多都 是一样的代码,这不符合程序员的一惯的懒惰的优良作风。那上面的代码又有什么问题呢?最起码有下面的几个问题:
(1)Context在这里起的作用是必须的吗?
(2)传进去的数据只能是String类型(写死的)
那怎么来解决这些问题呢?请看下面的例子:
public class GeneralListViewAdapter<T> extends BaseAdapter { private List<T> mListDatas = null; private IItemViewHolder mIViewHolder; private int mItemLayoutId; //private ItemContent<T> mItemContent; public GeneralListViewAdapter(int itemlayoutid,List<T> listdatas,IItemViewHolder iviewholder) { mListDatas = listdatas ; mIViewHolder = iviewholder; mItemLayoutId =itemlayoutid; } @Override public int getCount() { return mListDatas.size(); } @Override public T getItem(int position) { return mListDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertview, ViewGroup parent) { if (convertview == null || convertview.getTag() == null) { try { mIViewHolder = mIViewHolder.getClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } convertview = LayoutInflater.from(parent.getContext()).inflate(mItemLayoutId, parent,false); mIViewHolder.bindToItemView(convertview); convertview.setTag(mIViewHolder); } else{ mIViewHolder = (IItemViewHolder) convertview.getTag() ; } mIViewHolder.updataItemContent(getItem(position)); return convertview; } public interface IItemViewHolder { public abstract <T> void updataItemContent(T itemdata); public abstract void bindToItemView(View itemview); } }以上代码我们将不变部分进行了封装,变化的部分抽取成了接口。同时解决了上面的问题:Context实例我们通过传进来的父控件来获取,不再需要传递进来,传进的数据我们用泛型,并用在updataItemContent(T itemdata)方法中传出,这样,我们在写代码的时候只需要实现这个接口就行了,接口的两个方法也很好理解:一个是把自己绑定到View,一个是给view的属性更新数据。只需要这么多就行了,如果你觉得这样难以理解,写成这样可能更符合原来的思维方式吧!
public abstract class GeneralListViewAdapter<T> extends BaseAdapter { private List<T> mListDatas = null; private IItemViewHolder mIViewHolder; private int mItemLayoutId; //private ItemContent<T> mItemContent; public GeneralListViewAdapter(int itemlayoutid,List<T> listdatas,IItemViewHolder iviewholder) { mListDatas = listdatas ; mIViewHolder = iviewholder; mItemLayoutId =itemlayoutid; } @Override public int getCount() { return mListDatas.size(); } @Override public T getItem(int position) { return mListDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertview, ViewGroup parent) { if (convertview == null || convertview.getTag() == null) { try { mIViewHolder = mIViewHolder.getClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } convertview = LayoutInflater.from(parent.getContext()).inflate(mItemLayoutId, parent,false); bindToItemView(convertview); convertview.setTag(mIViewHolder); } else{ mIViewHolder = (IItemViewHolder) convertview.getTag() ; } updataItemContent(getItem(position)); return convertview; } public interface IItemViewHolder { // public abstract <T> void updataItemContent(T itemdata); // public abstract void bindToItemView(View itemview); } public abstract <T> void updataItemContent(T itemdata); public abstract void bindToItemView(View itemview); }
当然上面的代码只是一个简单的抽象和抽取,其实ListView还有很多可以优化的地方,比如,就像ListView与Adapter之间的观察者模式,其实我们可以做成让Adapter再做一回观察者,数据源做被观察者,这样就可以实现只要数据变化了,ListView就会自动更新,下一篇将实现上述能够自动更新的ListView
本文资源下载:点击打开链接:http://download.csdn.net/detail/xinxincement/9492966
相关文章推荐
- Node.js学习 - Route
- oracle表分区与索引分区
- Node.js学习 - Function
- 学习小结3
- C++ 中关于默认构造函数的一点困惑
- 剑指offer之编程(一)
- IntelliJ IDEA:Getting Started with Spring MVC, Hibernate and JSON实践
- Node.js学习 - Modules
- XCode-LibrarySearchPath和FramewrokSearchPath
- 函数调用的过程
- Invalid proguard configuration file path D:\...\proguard.cfg does not exist or is not a regular file
- iOS中通知中心的概念知识吧(objective - c版)
- Node.js学习 - Stream
- Node.js学习 - Buffer
- JAVA反射机制(及反射调用的性能简测)
- android之返回键与依次弹出返回栈
- VS 创建 使用C++ 静态类库(Dll)
- Java基础学习(三)—面向对象(上)
- Linux防火墙iptables学习笔记(三)iptables命令详解和举例[转载]
- effective c++读书笔记(一)