Android之ListView/GridView 优化
一、效率最低的getView实现
我们知道,ListView和GridView的显示都是通过Adapter的getView实现的。
ListView/GridView数据量较小时,我们的处理方式一般是这样的(效率最低的一种方式)
public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item_icon_text, null);
((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return item;
}
当数据量非常大时,这样每一次getView都会去inflate布局,效率太差,这会让我们的程序卡顿,滑动多了还会OOM。
二、利用Android已经提供了View缓存机制实现ViewHolder模式——实现View共享
我们注意到getView的第二个参数convertView,这个是View缓存机制的关键。简单的说就两点:
1.假设当前页面我们有7个item,那么前七次getView,这个convertView一开始都是null。因此我们需要inflate布局,这样我们得到7个convertView(convertView1——converView7)
2.假设我们往上翻页,现在Item8进入页面,item1出页面,此时Item8对应的getView中的convertView就是convertView1。
利用这个View缓存机制的特点,我们只需要将Item8的getView中convertView(即convertView1)的数据由item1更新为item8即可。也就是说item8和item1就实现了View的共享(共享convertView1)。(本来嘛,item8和item1永远不会在一个界面中一起出现,确实应该共享一些资源)
而这就是所谓的ViewHolder模式
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
List
Log.i("xerrard", "getView " + position + " " + convertView);
ViewHolder viewHolder = null;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.item, null);
viewHolder.image = (ImageView) convertView.findViewById(R.id.img);
viewHolder.text = (TextView) convertView.findViewById(R.id.txt);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.image.setImageBitmap(imgs.get(position));
viewHolder.text.setText(texts.get(position));
return convertView;
}
class ViewHolder{
ImageView image;
TextView text;
}
三、ListView /GridView的异步加载。
很多时候我们会需要再网上下载一些图片来进行显示,如果在主线程做下载的操作,这样很可能会造成ANR,所以需要子线程来实现。(即使是本地存储中的图片,也建议用子线程来实现,本地IO操作有时也会造成ANR)
我们使用android中的AsyncTask来实现下载的操作
/**
* Created by xuqiang on 15-12-16.
*/
public class ImageTask extends AsyncTask<String, Void, Bitmap> {
private ImageView iv;
String imgUrl;
public ImageTask(ImageView iv){
this.iv = iv;
} @Override
protected Bitmap doInBackground(String... param) {
imgUrl = param[0];
try {
URL url = new URL(imgUrl);
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream in = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(in);
if(bitmap!=null){
return bitmap;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
} @Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (result != null) {
// 通过 tag 来防止图片错位
if (iv.getTag() != null && iv.getTag().equals(imgUrl)) {
iv.setImageBitmap(result);
}
}
} @Override
protected void onPreExecute() {
super.onPreExecute();
}
}
然后在getView中,我们只需要将原本对ViewHolder的操作,传参数给ImageTask来处理
ImageTask imageTask = new ImageTask(viewHolder.image,position);
imageTask.execute(imgUrls.get(position));
四、ListView /GridView的异步加载中的错位问题解决
刚才我们知道,利用的android的View缓存机制,我们可以使用ViewHolder优化ListView/GridView的效率。但是在异步加载图片的过程中,正是因为这个View共享的机制,会造成图片错位的情况。
——当快速滑动的情况下,会出现item1和item8都显示部分的情况。
a.item1和item8共享一个convertView,而异步加载的情况下,是有可能会出现item8异步加载完毕准备显示时,item1还没有加载完毕,这样就会出现先convertView.setView(item8),然后convertView.setView(item1),这样原本应该显示item8的位置却显示了item1。
b.即使是先加载完Item1,再加载完Item8,也会给用户一种原本应该显示item8的地方先显示item1后再正常显示item8的感觉。
这个问题,我们如何解决。
最简单的解决方法就是网上说的,给 ImageView 设置一个 tag。
当 Item1 比 Item8 图片下载的快时, 你滚下去使 Item8 可见,这时 ImageView 的 tag 被设成了
Item8 的 URL, 当 Item1 下载完时,由于 Item1 不可见现在的 tag 是 Item8 的 URL,所以不满足条件,
虽然下载下来了但不会设置到 ImageView 上, tag 标识的永远是可见 view 中图片的 URL。
我们最后将这个最终的改进方案写下来
1.在主线程设置一个tag,
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
Log.i("xerrard", "getView " + position + " " + convertView);
ViewHolder viewHolder = null;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.item, null);
viewHolder.image = (ImageView) convertView.findViewById(R.id.img); convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.image.setTag(imgUrls.get(position));
ImageTask imageTask = new ImageTask(viewHolder.image);
imageTask.execute(imgUrls.get(position));
return convertView;
}
class ViewHolder{
ImageView image;
}
}
2.在异步的ImageTask设置图片的地方,判断Tag,确认Tag没有问题之后,再设置图片
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (result != null) {
// 通过 tag 来防止图片错位
if (iv.getTag() != null && iv.getTag().equals(imgUrl)) {
iv.setImageBitmap(result);
}
}
}
Android之ListView/GridView 优化的更多相关文章
- ym——Android之ListView性能优化
转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...
- Android之ListView性能优化——一行代码绑定数据——万能适配器
如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...
- Android之ListView性能优化
ListView滚动速度优化主要可以应用以下几点方法来实现: 1.使用Adapter提供的convertView convertView是Adapter提供的视图缓存机制,当第一次显示数据的时候,ad ...
- Android 开发ListView适配器优化
我们都知道Android中Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View.想过没有? 在我们的列 ...
- [Android Pro] ListView,GridView之LayoutAnimation特殊动画的实现
转载自:http://gundumw100.iteye.com/blog/1874545 LayoutAnimation干嘛用的?不知道的话网上搜一下. Android的Animation之Layou ...
- Android之ListView性能优化——使用ConvertView和ViewHolder
使用ConvertView和ViewHolder的优化是针对ListView的Adapter(BaseAdapter)的.这种优化的优点如下: 1)重用了ConveertView,在很大程度上减少了内 ...
- android入门 — ListView的优化
ListView的运行效率是比较低的,因为在getView()中每次都会将整个布局重新加载一遍,当ListView快速滚动的时候就会成为性能瓶颈. 调用View中的findViewById()方法获取 ...
- Android中ListView的优化
第一种方法 重用了convertView,很大程度上的减少了内存的消耗.通过判断convertView是否为null,是的话就需要产生一个视图出来,然后给这个视图数据,最后将这个视图返回给底层,呈献给 ...
- Android进阶笔记14:ListView篇之ListView性能优化
1. 首先思考一个问题ListView如何才能提高效率 ? 当convertView为空时候,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象.当convertView不 ...
随机推荐
- Application路径
根目录:StreamingAssets文件夹 #if UNITY_EDITOR string filepath = Application.dataPath +"/StreamingAsse ...
- [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】
题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...
- mysql数据库操作语句大全
一 . 常用mysql命令行命令 1 .启动MYSQL服务 net start mysql 停止MYSQL服务 net stop mysql 2 . netstat –na | findstr 3 ...
- 【POJ】3283 Card Hands
字典树. #include <iostream> #include <cstdio> #include <cstring> #include <string& ...
- bzoj1221
网络流与线性规划24题中的餐巾计划吧明显要拆点吧,把每一天拆成2个点,i,i+n起点 终点 容量 费用 s i inf c 每天都可以购买新毛巾 i ...
- 安装zabbix2.2.3
系统版本:CentOS 6.3_x86_64 zabbix版本:zabbix-2.2.3 zabbix服务端IP:172.16.10.72 1.yum安装LAMP环境 # yum -y install ...
- VirtualBox扩展Ubuntu磁盘空间
有时候我们在使用virtualBox虚拟机时,创建虚拟机时并没有考虑到所占用硬盘大小,后来可能磁盘空间不够用了. 以下方法可以帮你扩展虚拟机的存储空间(以下Ubuntu为例). 1. 在宿主机器进入V ...
- [JAVA关键字] static & final
JAVA十分常见的关键字static & final 总的来说final表示常量,即不可更改的:而static表示静态,即全局的 1. final 类:不能被继承 2. final 方法:能被 ...
- 动态规划——数位dp
通过先前在<动态规划——背包问题>中关于动态规划的初探,我们其实可以看到,动态规划其实不是像凸包.扩展欧几里得等是具体的算法,而是一种在解决问题中决策的思想.在不同的题目中,我们都需要根据 ...
- Dolls - 4160(简单二分图匹配)
题意:有一些箱子,大箱子可以套小箱子,但是必须h>h,w>w,l>l,求出来最外面能剩下几个箱子无法被嵌套. 分析:思考每个箱子都只会被别的箱子套一次,所以构成一二分匹配模型,只 ...