android ListView 中getview学习总结
最近在做android相关的开发,ListView中有一个图片错位的问题,今天查了很多人写的一些东西,所以记录下来,算是一种加深理解吧。
ListView是一个非常常用的控件,功能可以扩展的很丰富,而且与GridView有很多相似的地方。都可以存放大量数据。而且当我们需要比较复杂的布局时,一般用SimpleAdapter,或者继承BaseAdapter自己重写。
如果是继承ArrayAdapter,SimpleAdapter的时候,由于父类本身维护了一个List,所以当有数据更新的时候,尽量用adapter的add,这样可以保证getCount()返回的值是正确。
这里面涉及到的一个比较重要的重写函数就是getView
在getView中有三种方式实现view的返回。
第一种方式:
最简单也是最容易理解的是每一个view都通过inflate生成一个新的view进行返回
public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(context); View item = inflater.inflate(R.layout.list_item_icon_text, null); ((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap( return item;
}
这种方式,在数据量小的时候,劣势不明显,但是当一个listview里面有大量条目时,这种方式就显得非常浪费。因为每一次item的出现,消失或者更新时,都需要重新inflate。给内存造成了很大的消耗。
那么还有什么方式可以节省开销呢?
第二种方式:
我们看看getView函数里面conertview的是干啥的。查看官方文档后发现:
convertView - The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see Adapter.getViewTypeCount() and Adapter.getItemViewType(int)).
注:
getViewTypeCount()是用来当listview中有不同的种类的item,比如分割线之类的时候,用getItemViewType返回某个item的类型,然后坐不同的
原来converView是用来重用view的。经过查找别的资料。找到了一张比较经典的图如下:
这张图清楚的描述了listview是如何重用view的。listview通过getview分别请求所有可见项目。此时converview是空的。
当item1滑动出屏幕后,item8从下面滑动出来,此时又要调用getview,但是此时的converview已经不再为空了,而是上次一划出屏幕的item1,此时我们只需要重新修改下item1的数据,而不必重新创建一个新的view。
这样就节省了内存。
那么由此我们得到了第二种方式
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, parent, false);
}
((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
这种方式里面,我们通过converview找到对应需要修改的text和ico,然后修改数据,进行返回。
有人会说,上面不已经解决了重用的问题了么,还有第三种方式?
那么我们下面看看google推荐的第三种方式是怎么实现的。
static class ViewHolder {
TextView text;
ImageView icon;
}
这里定义了一个内部静态类,
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder; if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
然后用convertView.setTag(holder)的方式将之前通过findViewById找到的textview与ImageView放入converivew对象中。
这样当再次重用converview的时候,就不必再次利用findViewById来查找了,省掉了开销。
最后引用别人的一张图,来说明三种方式的性能。
写了这么多,还有个小问题需要解决:
当我们是异步加载图片等资源的时候,由于下载速度不同,所以重用view之后,可能会造成图片的错乱。
举个简单例子:
假如上面item1和item8两个图片下载速度不同,item8下载比较快。
那么当item1划出屏幕,item8出现的时候,item8会先显示下载好的图片,接下来item1也下载好了,于是下载图片的线程又将item1(也就是与item8共用的view)设置为item1下载好的图片。
所以在这里我们必须去标记下,当前显示的是哪个view,于是最简单的方法就是给每一个holder.icon设置一个tag(也就是图片的url),当后台下载完图片后,将holder.icon的tag与url对比,如果不同,就说明不是这个view的图片,那么就不去加载。
android ListView 中getview学习总结的更多相关文章
- [转][Android] ListView中getView的原理+如何在ListView中放置多个item
ListView 和 Adapter 的基础 工作原理: ListView 针对List中每个item,要求 adapter “给我一个视图” (getView). 一个新的视图被返回并显示 如果 ...
- 转:ListView中getView的工作原理
ListView中getView的工作原理: [1]ListView asks adapter “give me a view” (getView) for each item of the list ...
- android listview中item通过viewpager实现《IT蓝豹》
android listview中item通过viewpager实现 android listview中item通过viewpager实现,每一个item都支持viewpager实现图片切换功能.本项 ...
- Android ListView 中的checkbox
Q:ListView + CheckBox 当上下滚动的时候有事会自动选中或取消 A:这个与ListView的缓存机制有关.当你屏幕滚动后,ListView中的item选项视图先检查缓存中是否有视图, ...
- Android ListView中Item点击事件失效解决方案
欢迎关注公众号,每天推送Android技术文章,二维码如下:(可扫描) 在平常的开发过程中,我们的ListView可能不只是简单的显示下文本或者按钮,更多的是显示复杂的布局,这样的话,我们就得自己写布 ...
- 关于ListView中getView被重复调用的问题
我用ListView显示数据时,自定义了一个适配器(extends ArrayAdapter),然后重写了getView方法,现在出现一个问题,就是这个getView()方法被重复调用了,比如我的_d ...
- android ListView 与GridView 学习总结(五)
ListView的使用总结 基本使用: 步骤:在布局文件中定义一个ListView控件-在活动中获得ListView的实例-获得适配器adapter的实例并且传入三个参数-把适配器对象传递给lis ...
- Android Listview中Button按钮点击事件冲突解决办法
今天做项目时,ListView中含有了Button组件,心里一早就知道肯定会有冲突,因为以前就遇到过,并解决过,可惜当时没有记录下来. 今天在做的时候,继续被这个问题郁闷了一把,后来解决后,赶紧来记录 ...
- Android,LIstView中的OnItemClick点击无效的解决办法
在List_Item布局文件中的根节点加上如下背景标黄的这一行 <?xml version="1.0" encoding="utf-8"?> < ...
随机推荐
- C#开源框架(整理)
http://www.cnblogs.com/chinanetwind/p/3715809.html http://www.cnblogs.com/chinanetwind/p/3715813.htm ...
- (转)android中利用 ViewPage 实现滑动屏
最近实现了这样的一个效果:滑动界面出现拖拽效果,可翻动3屏,也可点击按钮翻动页面. 主要利用android.support.v4.view.ViewPager控件来实现. 第一个界面: 滑动屏幕: 换 ...
- C语言——内存分配
1.在C语言的运行过程中,需要内存来存储数据.C语言使用的内存总体可以分为两类:一类是静态区,一类是动态区.2.静态数据存储区包含:只读数据区.已初始化的读写数据区.未初始化的读写数据区 动态 ...
- 用python产生一个好的秘钥
import os os.urandom(24)
- 转】MyEclipse使用总结——在MyEclipse中设置jsp页面为默认utf-8编码
原博文出自于:http://www.cnblogs.com/xdp-gacl/p/3496161.html 感谢! 在MyEclispe中创建Jsp页面,Jsp页面的默认编码是"ISO-88 ...
- ControlsFX8.0.2中对话框无法判断是否显示的修改
在org.controlsfx.dialog.FXDialog.java中加入 public abstract boolean isShowing(); 在org.controlsfx.dialog. ...
- LeetCode283:Move Zeros
Given an array nums, write a function to move all 0's to the end of it while maintaining the relativ ...
- HDU 4284Travel(状压DP)
HDU 4284 Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1 ...
- 数据库:mongodb与关系型数据库相比的优缺点
与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度:举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精 ...
- C#.Net中的非托管代码清理
帮助其它项目组Review代码过程,发现有些地方实现了IDispose接口,同时也发现了一些关于IDispose的问题: 1.A类型实现了IDispose接口,B类型里面含有A类型的字段,B类型没有实 ...