android listview 异步加载图片并防止错位

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作.

如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题。

我简单分析一下:

当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView.

当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Item8 复用的是

Item1 的 view 如果没有异步不会有任何问题,虽然 Item8 和 Item1 指向的是同一个 view,但滑到

Item8 时刷上了 Item8 的数据,这时 Item1 的数据和 Item8 是一样的,因为它们指向的是同一块内存,

但 Item1 已滚出了屏幕你看不见。当 Item1 再次可见时这块 view 又涮上了 Item1 的数据。

 

但当有异步下载时就有问题了,假设 Item1 的图片下载的比较慢,Item8 的图片下载的比较快,你滚上去

使 Item8 可见,这时 Item8 先显示它自己下载的图片没错,但等到 Item1 的图片也下载完时你发现

Item8 的图片也变成了 Item1 的图片,因为它们复用的是同一个 view。 如果 Item1 的图片下载的比

Item8 的图片快, Item1 先刷上自己下载的图片,这时你滑下去,Item8 的图片还没下载完, Item8

会先显示 Item1 的图片,因为它们是同一快内存,当 Item8 自己的图片下载完后 Item8 的图片又刷成

了自己的,你再滑上去使 Item1 可见, Item1 的图片也会和 Item8 的图片是一样的,

因为它们指向的是同一块内存。

 

最简单的解决方法就是网上说的,给 ImageView 设置一个 tag, 并预设一个图片。

当 Item1 比 Item8 图片下载的快时, 你滚下去使 Item8 可见,这时 ImageView 的 tag 被设成了

Item8 的 URL, 当 Item1 下载完时,由于 Item1 不可见现在的 tag 是 Item8 的 URL,所以不满足条件,

虽然下载下来了但不会设置到 ImageView 上, tag 标识的永远是可见 view 中图片的 URL。

关键代码如下:

复制代码
public View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {holder = new ViewHolder();convertView = LayoutInflater.from(context).inflate(R.layout.list_item, null);holder.img = (ImageView) convertView.findViewById(R.id.userimage);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}User user = list.get(position);// 给 ImageView 设置一个 tagholder.img.setTag(user.getImgUrl());// 预设一个图片holder.img.setImageResource(R.drawable.ic_launcher);final String tmpImageUrl = user.getImgUrl();if (user.getImgUrl() != null && !user.getImgUrl().equals("")) {Bitmap bitmap = imageLoader.loadImage(holder.img, user.getImgUrl(),new ImageDownloadCallBack() {@Overridepublic void onImageDownloaded(ImageView imageView,Bitmap bitmap) {// 通过 tag 来防止图片错位if (imageView.getTag() != null&& imageView.getTag().equals(tmpImageUrl)) {imageView.setImageBitmap(bitmap);}}});if (bitmap != null) {holder.img.setImageBitmap(bitmap);}}return convertView;
}
复制代码

我参考网上资料写了一个 listview 异步加载图片的 DEMO:

(1) 使用线程池

 没有线程池,当图片非常多,快速滑动  listview 时由于下载每个图片都开了一个线程,

 可能出现 OOM (out of memory)。

(2) 内存、文件双缓存

 这里也使用 SoftReference 软引用  

复制代码
/*** 图片异步加载类* * @author Leslie.Fang* @company EnwaySoft* */
public class AsyncImageLoader {// 最大线程数private static final int MAX_THREAD_NUM = 10;private Map<String, SoftReference<Bitmap>> imageCaches = null;private FileUtil fileUtil;// 线程池private ExecutorService threadPools = null;public AsyncImageLoader(Context context) {imageCaches = new HashMap<String, SoftReference<Bitmap>>();fileUtil = new FileUtil(context);}public Bitmap loadImage(final ImageView imageView, final String imageUrl,final ImageDownloadCallBack imageDownloadCallBack) {final String filename = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);final String filepath = fileUtil.getAbsolutePath() + "/" + filename;// 先从软引用中找if (imageCaches.containsKey(imageUrl)) {SoftReference<Bitmap> reference = imageCaches.get(imageUrl);Bitmap bitmap = reference.get();// 软引用中的 Bitmap 对象可能随时被回收// 如果软引用中的 Bitmap 已被回收,则从文件中找if (bitmap != null) {Log.i("aaaa", "cache exists " + filename);return bitmap;}}// 从文件中找if (fileUtil.isBitmapExists(filename)) {Log.i("aaaa", "file exists " + filename);Bitmap bitmap = BitmapFactory.decodeFile(filepath);// 重新加入到内存软引用中imageCaches.put(imageUrl, new SoftReference<Bitmap>(bitmap));return bitmap;}// 软引用和文件中都没有再从网络下载if (imageUrl != null && !imageUrl.equals("")) {if (threadPools == null) {threadPools = Executors.newFixedThreadPool(MAX_THREAD_NUM);}final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 111 && imageDownloadCallBack != null) {Bitmap bitmap = (Bitmap) msg.obj;imageDownloadCallBack.onImageDownloaded(imageView,bitmap);}}};Thread thread = new Thread() {@Overridepublic void run() {Log.i("aaaa", Thread.currentThread().getName()+ " is running");InputStream inputStream = HTTPService.getInstance().getStream(imageUrl);Bitmap bitmap = BitmapFactory.decodeStream(inputStream);// 图片下载成功重新缓存并执行回调刷新界面if (bitmap != null) {// 加入到软引用中imageCaches.put(imageUrl, new SoftReference<Bitmap>(bitmap));// 缓存到文件系统fileUtil.saveBitmap(filepath, bitmap);Message msg = new Message();msg.what = 111;msg.obj = bitmap;handler.sendMessage(msg);}}};threadPools.execute(thread);}return null;}public void shutDownThreadPool() {if (threadPools != null) {threadPools.shutdown();threadPools = null;}}/*** 图片下载完成回调接口* */public interface ImageDownloadCallBack {void onImageDownloaded(ImageView imageView, Bitmap bitmap);}
}
复制代码

  DEMO 下载地址:http://pan.baidu.com/s/1sjttuFj

博客转载自:

http://www.cnblogs.com/lesliefang/p/3619223.html

 

转载于:https://www.cnblogs.com/ycxyyzw/p/3813743.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/473283.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python最实用的25个小技巧

Python 是一种通用的高级编程语言。用它可以做许多事&#xff0c;比如开发桌面 GUI 应用程序、网站和 Web 应用程序等。 并且&#xff0c;通过处理常见的编程任务&#xff0c;Python 能让开发者专注应用程序的核心功能。此外&#xff0c;Python 语言的简单语法规则进一步简化了…

LeetCode 1705. 吃苹果的最大数目(优先队列)

文章目录1. 题目2. 解题1. 题目 有一棵特殊的苹果树&#xff0c;一连 n 天&#xff0c;每天都可以长出若干个苹果。 在第 i 天&#xff0c;树上会长出 apples[i] 个苹果&#xff0c;这些苹果将会在 days[i] 天后&#xff08;也就是说&#xff0c;第 i days[i] 天时&#xff0…

Action重定向总结

[HttpPost]public ActionResult StudentList( string StudName, string studName, DateTime BirthDay, FormCollection form, string controller, string Action, StudentModels student){//其中StudName为aspx页面中标签的name属性(StudName不区分大小写)//其中BirthDay为页面…

全面系统地总结Linux的基本操作(上)

1、 Linux文件和目录 Windows 和 Linux 文件系统 在 windows 平台下&#xff0c;打开"计算机"&#xff0c;我们看到的是一个个的驱动器盘符&#xff1a;每个驱动器都有自己的根目录结构&#xff0c;这样形成了多个树并列的情形&#xff0c;如图所示&#xff1a; 在 …

Pytorch 神经网络nn模块

文章目录1. nn模块2. torch.optim 优化器3. 自定义nn模块4. 权重共享参考 http://pytorch123.com/ 1. nn模块 import torch N, D_in, Hidden_size, D_out 64, 1000, 100, 10torch.nn.Sequential 建立模型&#xff0c;跟 keras 很像 x torch.randn(N, D_in) y torch.randn…

全面系统地总结Linux的基本操作(下)

4、 Linux命令-系统管理 4.1 查看日历:cal cal 命令用于查看当前日历&#xff0c;-y 显示整年日历&#xff1a; 4.2 显示或设置日期:date 设置时间格式&#xff08;需要管理员权限&#xff09;&#xff1a; date [MMDDhhmm[[CC]YY][.ss]] format CC 为年前两位 yy 为年的后…

腾讯QQ企业邮箱POP3/SMTP设置

腾讯企业邮箱支持通过client进行邮件管理。POP3/SMTP协议收发邮件server地址分别例如以下。接收邮件server&#xff1a;pop.exmail.qq.com (port 110)发送邮件server&#xff1a;smtp.exmail.qq.com (port 25)同一时候支持SSL加密方式登录&#xff0c;此时须要更改一下port号。…

免费个人博客:使用hexo+github搭建详细教程

前言 使用github pages服务搭建博客的好处有&#xff1a; 全是静态文件&#xff0c;访问速度快&#xff1b;免费方便&#xff0c;不用花一分钱就可以搭建一个自由的个人博客&#xff0c;不需要服务器不需要后台&#xff1b;可以随意绑定自己的域名&#xff0c;不仔细看的话根…

LeetCode 1235. 规划兼职工作(动态规划+二分查找)

文章目录1. 题目2. 解题1. 题目 你打算利用空闲时间来做兼职工作赚些零花钱。 这里有 n 份兼职工作&#xff0c;每份工作预计从 startTime[i] 开始到 endTime[i] 结束&#xff0c;报酬为 profit[i]。 给你一份兼职工作表&#xff0c;包含开始时间 startTime&#xff0c;结束…

刷新页面,无论点击多少次让Element UI的Message消息提示弹出一个

一、遇到的问题 Element UI的Message消息提示是点击一次触发一次的。在开发的时候经常会作为一些校验提示&#xff0c;但是公司的测试人员在进行测试时会一直点&#xff0c;然后就会出现如下图的情况。虽然客户使用的时候一般来说不会出现这种情况&#xff08;毕竟客户不会闲着…

如何让二维码自适应浏览器的尺寸

一、遇到的问题&#xff1a; 正常浏览网页&#xff0c;二维码正常显示&#xff0c;但是随着浏览器的扩大与缩小&#xff0c;二维码尺寸不会随着屏幕自适应 正常浏览&#xff08;截取部分&#xff09;&#xff1a; 缩小浏览器&#xff08;截取部分&#xf…

E6全部刷机包

此版本号基于R533_G_11.11.10P_GSZMCAUT679DA01B_LP064DA_T679DA_S005_E001_P002_R001_G004_1FF.sbf制作耳机接听或挂机正常内置Loader&#xff08;asmotoe2&#xff09;、Console&#xff08;网上的大侠&#xff09;、showQ&#xff08;bint大侠&#xff09;、SetupPKG&#x…

LeetCode 330. 按要求补齐数组(贪心)

文章目录1. 题目2. 解题1. 题目 给定一个已排序的正整数数组 nums&#xff0c;和一个正整数 n 。 从 [1, n] 区间内选取任意个数字补充到 nums 中&#xff0c;使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示。请输出满足上述要求的最少需要补充的数字个数…

系统总结vue组件间通信、数据传递(父子组件,同级组件)

总结一下对vue组件通信的理解和使用。一、组件目录结构 父组件&#xff1a;app.vue子组件&#xff1a;page1.vue子组件&#xff1a;page2.vue 父组件 app.vue <template><div id"app"><p>请输入单价: <input type"text" v-model&qu…

LeetCode 1224. 最大相等频率(哈希)

文章目录1. 题目2. 解题1. 题目 给出一个正整数数组 nums&#xff0c;请你帮忙从该数组中找出能满足下面要求的 最长 前缀&#xff0c;并返回其长度&#xff1a; 从前缀中 删除一个 元素后&#xff0c;使得所剩下的每个数字的出现次数相同。 如果删除这个元素后没有剩余元素…

从零开始,手把手交给你vue如何新建一个项目

vue创建项目&#xff08;npm安装→初始化项目&#xff09; 第一步npm安装 首先&#xff1a;先从nodejs.org中下载nodejs 图1 双击安装&#xff0c;在安装界面一直Next 图2 图3 图4 直到Finish完成安装。 打开控制命令行程序&#xff08;CMD&#xff09;,检查是否正常 图5 …

数学图形(1.33) 棕子曲线

#http://www.mathcurve.com/courbes2d/vasques/vasques.shtml vertices 10000 t from 0 to (8*PI) a rand_int2(1, 30) b rand_int2(1, 4) n 8 x cos(n*t - t)*cos(n*t) y cos(n*t)^2 a 10 x x*a y y*a 相关软件参见:数学图形可视化工具,使用自己定义语法的脚本代码生…

LeetCode 1278. 分割回文串 III(区间DP)

文章目录1. 题目2. 解题1. 题目 给你一个由小写字母组成的字符串 s&#xff0c;和一个整数 k。 请你按下面的要求分割字符串&#xff1a; 首先&#xff0c;你可以将 s 中的部分字符修改为其他的小写英文字母。接着&#xff0c;你需要把 s 分割成 k 个非空且不相交的子串&…

原生态HTML文件上传与下载

文件下载 传统的文件下载有两种方法&#xff1a; 使用<a/>标签&#xff0c;href属性直接连接到服务器的文件路径window.location.href"url" 这两种方法效果一样。但有个很大的问题&#xff0c;如果下载出现异常&#xff08;连接路径失效、文件不存在、网络问…

Jquery 常用总结

获取元素的宽度: 如果用$(ele).attr("width")获取的值不带px 如果用$(ele).css("width")获取的值带px //获取鼠标坐标 $(function() { $("#Button2").click(function(event) { alert(event.p…