一、效率最低的getView实现

我们知道,ListView和GridView的显示都是通过Adapter的getView实现的。

ListView/GridView数据量较小时,我们的处理方式一般是这样的(效率最低的一种方式)

1 public View getView(int position, View convertView, ViewGroup parent) {
2      View item = mInflater.inflate(R.layout.list_item_icon_text, null);
3      ((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
4      ((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
5      (position & 1) == 1 ? mIcon1 : mIcon2);
6      return item;
7 }

当数据量非常大时,这样每一次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模式

        @Overridepublic View getView(int position, View convertView, ViewGroup arg2) {ListLog.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来实现下载的操作

 1 /**
 2  * Created by xuqiang on 15-12-16.
 3  */
 4 public class ImageTask extends AsyncTask<String, Void, Bitmap> {
 5     private ImageView iv;
 6     String imgUrl;
 7     public ImageTask(ImageView iv){
 8         this.iv = iv;
 9     }
10
11     @Override
12     protected Bitmap doInBackground(String... param) {
13         imgUrl = param[0];
14         try {
15             URL url = new URL(imgUrl);
16             try {
17                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
18                 InputStream in = conn.getInputStream();
19                 Bitmap bitmap = BitmapFactory.decodeStream(in);
20                 if(bitmap!=null){
21                     return bitmap;
22                 }
23             } catch (IOException e) {
24                 // TODO Auto-generated catch block
25                 e.printStackTrace();
26             }
27         } catch (MalformedURLException e) {
28             // TODO Auto-generated catch block
29             e.printStackTrace();
30         }
31         return null;
32     }
33
34     @Override
35     protected void onPostExecute(Bitmap result) {
36         super.onPostExecute(result);
37         if (result != null) {
38             // 通过 tag 来防止图片错位
39             if (iv.getTag() != null && iv.getTag().equals(imgUrl)) {
40                 iv.setImageBitmap(result);
41             }
42         }
43     }
44
45     @Override
46     protected void onPreExecute() {
47         super.onPreExecute();
48     }
49 }

然后在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,

 1         @Override
 2         public View getView(int position, View convertView, ViewGroup arg2) {
 3             Log.i("xerrard", "getView " + position + " " + convertView);
 4             ViewHolder viewHolder = null;
 5             if(convertView == null){
 6                 viewHolder = new ViewHolder();
 7                 convertView = inflater.inflate(R.layout.item, null);
 8                 viewHolder.image = (ImageView) convertView.findViewById(R.id.img);
 9
10                 convertView.setTag(viewHolder);
11             }else{
12                 viewHolder = (ViewHolder) convertView.getTag();
13             }
14             viewHolder.image.setTag(imgUrls.get(position));
15             ImageTask imageTask = new ImageTask(viewHolder.image);
16             imageTask.execute(imgUrls.get(position));
17             return convertView;
18         }
19         class ViewHolder{
20             ImageView image;
21         }
22     }

2.在异步的ImageTask设置图片的地方,判断Tag,确认Tag没有问题之后,再设置图片

 1     @Override
 2     protected void onPostExecute(Bitmap result) {
 3         super.onPostExecute(result);
 4         if (result != null) {
 5             // 通过 tag 来防止图片错位
 6             if (iv.getTag() != null && iv.getTag().equals(imgUrl)) {
 7                 iv.setImageBitmap(result);
 8             }
 9         }
10     }

转载于:https://www.cnblogs.com/xerrard/p/5052734.html

Android之ListView/GridView 优化相关推荐

  1. ym——Android之ListView性能优化

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! Android之ListView性能优化 假设有看过我写过的15k面试题的朋友们一定知 ...

  2. Android 使用Listview的优化

    Listview是Android中很重要的一个组件,在开发过程中使用到的Listview能站到30%,在新手开发过程中,往往会忽略对Listview的优化,在上一个项目的开发中,确实用到了很多List ...

  3. Android中ListView数据处理优化

    来自:OPEN经验库 原帖:http://www.open-open.com/lib/view/open1330132229874.html Android 应用开发中,采用ListView组件来展示 ...

  4. Android中ListView的优化

    ListView的优化方案有很多,主要是以下几点         1.  重用了convertView,减少了内存消耗.通过判断convertView是否为null,是的话就需要产生一个ViewHol ...

  5. Android Studio ListView框架+优化安卓应用市场实例

    直接使用ListView的基本步骤 获取数据 创建适配器 绑定适配器 需要实现重写的函数: getCount() 获取数据长度 getItem (int position) 获取项资源 getItem ...

  6. android中Listview的优化技巧

    2019独角兽企业重金招聘Python工程师标准>>> 减少内存中view对象的创建个数(明显提高效率)       复用历史缓存的view对象,减少Android内存消耗 减少子孩 ...

  7. Android ListView性能优化实例讲解

    前言: 对于ListView,大家绝对都不会陌生,只要是做过Android开发的人,哪有不用ListView的呢? 只要是用过ListView的人,哪有不关心对它性能优化的呢? 关于如何对ListVi ...

  8. Android PullToRefresh (ListView GridView 下拉刷新) 使用详解

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38238749,本文出自:[张鸿洋的博客] 群里一哥们今天聊天偶然提到这个git ...

  9. Android在ListView中嵌套一个GridView时只显示一行的原因及解决方法

    在之前的编程里,我还没有遇到过要在一个ListView中嵌套一个GridView或是在一个GridView中嵌套一个ListView.所以今天事儿来了!我花了一将近3个小时,找到了为什么我在一个Lis ...

  10. Android之ListView原理学习与优化总结

    在整理前几篇文章的时候有朋友提出写一下ListView的性能优化方面的东西,这个问题也是小马在面试过程中被别人问到的-..今天小马就借此机会来整理下,网上类似的资料蛮多的,倒不如自己写一篇,记录在这个 ...

最新文章

  1. 创建Swap交换空间
  2. 中国、意大利等国研究员用AI 发现新的月球陨石坑 | AI日报
  3. Acwing第 41 场周赛【完结】
  4. nyoj117求逆序数 并归排序法
  5. Linux网络编程服务器模型选择之并发服务器(下)
  6. JAVA---事件适配器----用内部类,匿名类实现事件处理
  7. Android数据存储之SQLite数据库存储
  8. RedHat红帽RHEL7安装与使用,VMware Workstation16 Pro虚拟机的安装与使用
  9. java学生管理系统登录注册_Java程序---学生管理系统的登录和注册
  10. 微信小程序java python node医疗微服务系统医院预约挂号系统
  11. 【OpenCV-Python】教程:5-3 光流
  12. IoT开发——WIFI模块ESP8266 RTOS SDK V3.0.0环境搭建
  13. VUE 首屏加载时间优化
  14. 通过Charmed Ceph 在 H3C UniServer R4950 G5 服务器上 部署独立的Ubuntu Ceph 存储集群
  15. 白鹭引擎王泽:重度H5游戏性能优化技巧标题的文章
  16. 使用IText7 生成PDF文档
  17. 麦肯锡三部曲_人际连接三部曲
  18. IdentityServer4实战详解
  19. mw325r 服务器无响应),水星(MERCURY)MW325R路由器连不上网怎么办?
  20. 边沿捕获寄存器-Verilog

热门文章

  1. 客户端登陆服务器用户名验证
  2. ./configure: error: the HTTP rewrite module requires the PCRE library.
  3. Hadoop2.2.0中HDFS的高可用性实现原理
  4. Autodesk Map 3D 2012 新功能介绍
  5. Linux 基本网络配置
  6. 专注于钢铁行业电子商务的服务网站,钢铁行业的网上贸易市场 一起成长
  7. SecureCRT的logon action登录跳转设置
  8. linux关于bashrc与profile的区别(转)
  9. Spring Cloud 2020 年路线图
  10. Linux 正在吞噬 Windows 和 Chrome OS!