一、效率最低的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没有问题之后,再设置图片

在gridview的getview()方法中iv应该是image
 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     }
参考链接 http://www.cnblogs.com/xerrard/p/5052734.html

gridview中的图片错乱解决办法相关推荐

  1. php怎么显示不了图片,php显示不了图片的解决办法,

    php显示不了图片的解决办法PHP不能显示图片的解决方案,Php不能显示图片,因为源代码中除了img输出还有其他输出.解决方法是在调用头之前取消任何输出. 推荐: <PHP视频教程> 具体 ...

  2. docx转doc时,防止公式被转成图片的解决办法

    [转载]docx转doc时,防止公式被转成图片的解决办法 编辑社回复需要doc(Word 97-2003)格式的文档,可是将docx(Word 2007+)另存为doc格式时,发现公式被转成了图片.其 ...

  3. python读取excel图片尺寸_Python读取excel中的图片完美解决方法

    excel中有图片是很常见的,但是通过python读取excel中的图片没有很好的解决办法. 网上找了一种很聪明的方法,原理是这样的: 1.将待读取的excel文件后缀名改成zip,变成压缩文件. 2 ...

  4. 异常“只能在执行Render()的过程中调用RegisterForEventValidation”的解决办法(转)...

    当出现下面的异常的时候: 只能在执行Render()的过程中调用RegisterForEventValidation 当出现的异常的提示: 异常详细信息: System.InvalidOperatio ...

  5. 因为返回有true ajax提示进入错误,jquery ajax中error返回错误解决办法

    转自:https://www.jb51.net/article/72198.htm 进入百度搜索此问题,发现有人这么说了一句 Jquery中的Ajax的async默认是true(异步请求),如果想一个 ...

  6. html背景图片拉伸解决办法

    html背景图片拉伸解决办法 body {background-size: 100% 100%; //关键代码,直接拉伸背景图background-image: url("img/99.jp ...

  7. C#界面设计--5--Bitmap.save保存图片时: GDI+ 中发生一般性错误 解决办法

    Bitmap.save保存图片时: GDI+ 中发生一般性错误 解决办法 源程序: var date = DateTime.Now.ToString("yyyy-MM-dd");/ ...

  8. 关于matlab中help无法使用的解决办法(点开后是空白)

    关于matlab中help无法使用的解决办法(点开后是空白) 点击matlab"主页",在上面一排图标中找到"预设" 在出现的页面中最左边一栏点击"帮 ...

  9. Django中的跨域解决办法 基于后端的跨域解决方案

    Django中的跨域解决办法 基于后端的跨域解决方案 1 何为跨域 在浏览器中,只要发送请求的URL的协议.域名.端口号这三者中的任意一个与当前页面地址的协议.域名.端口号不同,则称之为跨域.当发生这 ...

最新文章

  1. android128 zhihuibeijing 科大讯飞 语音识别
  2. java 类 赋值_Java实现不同的类的属性之间相互赋值
  3. pku 2195 Going Home KM最小权匹配问题
  4. SmartRF Flash Programmer1.6.2打不开程序界面问题
  5. vtk鼠标不交互_vtk 各种不同的鼠标交互方式
  6. 2的32次方减1用python,第二章python入门
  7. java ios压缩_iOS与Java服务器GZip压缩问题【转】
  8. ThinkPHP多次重复提交问题的根源
  9. 论文浅尝 | Improved Neural Relation Detection for KBQA
  10. 欧几里得算法及其扩展
  11. 小区物业管理代码实现_全区58个老旧小区有了新“管家”
  12. Android异常 Eclipse编译应用时出现 com.android.dx.cf.iface.parseexception
  13. 测试用例编写八大要素
  14. 交通灯系统设计 educoder实训项目 logisim实现
  15. C# 判断是不是非负数
  16. 【工程光学】理想光学系统
  17. 利用flex布局在父元素和子元素宽高不明的情况下设置某一子元素剩余父元素的宽高
  18. js对象转byte数组
  19. C++线程编程-设计无锁的并发数据结构
  20. Clickhouse 分布式子查询——global in/join(慎用慎用)

热门文章

  1. 3 photolemur 样式下载_全自动照片美化软件Photolemur mac特别版
  2. ShadeGraph教程之节点详解4:Master Nodes
  3. java服务器端分页_使用数据表的服务器端分页
  4. 绒毛动物探测器:通过TensorFlow.js中的迁移学习识别浏览器中的自定义对象
  5. Abp vnext Web应用程序开发教程 3 —— 创建、更新和删除书籍
  6. 电子邮件地址验证:详细解释,生产质量WPF文本框代码
  7. 遍历同辈节电的方法_jQuery遍历节点
  8. python 两点曲线_python机器学习分类模型评估
  9. java mina文件传输_如何将Apache MINA FTP服务器中上传的文件重定向到数据库?
  10. c语言长度宏定义运算符,C语言在宏定义中使用语句表达式和预处理器运算符