[Android]ListView的Adapter.getView()方法中延迟加载图片的优化
以下内容为原创,欢迎转载,转载请注明
来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4139998.html
举个例子吧,以好友列表为例
ListView中每个Item表示一个好友,每个好友中都有一个头像,需要从服务端加载到本地,然后显示在item中。
显然,启动加载图片的过程应该是在getView()方法中触发,启动一个线程,然后下载头像图片。这里使用我写的一个开源框架ImageLoaderSample(https://github.com/wangjiegulu/ImageLoaderSample)来加载图片,并实现内存缓存和本地缓存。
额--这里不再介绍ImageLoaderSample的用法了,给个传送门:http://www.cnblogs.com/tiantianbyconan/p/3574131.html
再来看看getView()方法的调用时机:
1. Adapter调用NotifyDataChanged的时候
2. ListView滚动时,也就是convertView不断复用的时候。
也就是说,每当ListView滚动时,getView()方法不断被调用,图片下载的过程不断地执行(当然,ImageLoaderSample中会有缓存,但是内存缓存时有限的,如果内存缓存中找不到要显示的图片,那就需要到文件缓存中查找,需要进行io读写,这个也是相对比较耗时的),显然,这里面还有优化的余地。
怎么去优化这里?只要让ListView滚动的时候图片显示的时候不要去进行io读写就好了,具体逻辑如下:
-如果调用GetView方法时,ListView处于停止状态,则先去内存中查找头像图片;如果内存图片存在,则显示内存中保存好的图片;如果内存图片不存在,则继续到文件缓存中找,如果文件缓存图片存在,则显示文件缓存中的图片;如果文件缓存图片不存在,则根据url去网络下载这张图片,然后显示;
-如果调用getView方法时,ListView处于滚动状态,则去内存中查找头像的图片;如果内存图片存在,则显示内存中保存好的图片;如果内存图片不存在,则显示一张默认的图片(省去了从文件缓存中找图片和网络中去请求图片的步骤)。
这样的话,我们就必须要改写BaseAdapter,让它能够监测ListView的滚动状态,并在Adapter中可以获取到当前ListView的滚动状态。所以改造BaseAdapter,ABaseAdapter(https://github.com/wangjiegulu/AndroidBucket/blob/master/src/com/wangjie/androidbucket/adapter/ABaseAdapter.java):
1 package com.wangjie.androidbucket.adapter; 2 3 import android.widget.*; 4 import com.wangjie.androidbucket.adapter.listener.OnAdapterScrollListener; 5 6 /** 7 * Author: wangjie 8 * Email: tiantian.china.2@gmail.com 9 * Date: 12/3/14. 10 */ 11 public abstract class ABaseAdapter extends BaseAdapter implements AbsListView.OnScrollListener { 12 private OnAdapterScrollListener onAdapterScrollListener; 13 /** 14 * 当前listview是否属于滚动状态 15 */ 16 private boolean isScrolling; 17 18 public boolean isScrolling() { 19 return isScrolling; 20 } 21 22 public void setOnAdapterScrollListener(OnAdapterScrollListener onAdapterScrollListener) { 23 this.onAdapterScrollListener = onAdapterScrollListener; 24 } 25 26 protected ABaseAdapter(AbsListView listView) { 27 listView.setOnScrollListener(this); 28 } 29 30 @Override 31 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 32 if (null != onAdapterScrollListener) { 33 onAdapterScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 34 } 35 } 36 37 @Override 38 public void onScrollStateChanged(AbsListView view, int scrollState) { 39 if (null != onAdapterScrollListener) { 40 onAdapterScrollListener.onScrollStateChanged(view, scrollState); 41 } 42 43 // 设置是否滚动的状态 44 if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { // 不滚动状态 45 isScrolling = false; 46 this.notifyDataSetChanged(); 47 } else { 48 isScrolling = true; 49 } 50 } 51 }
如上述代码所示,该Adapter实现了AbsListView.OnScrollListener,并在构造方法中给ListView绑定了OnScrollListener,在实现的onScrollStateChanged方法中获取到当前滚动状态,并且保存这个状态isScrolling,并暴露isScrolling()方法给外面。
OnAdapterScrollListener这个接口是继承了AbsListView.OnScrollListener,因为这里在Adapter中一景设置了OnScrollListener了,所以如果在外面设置了新的OnScrollListener的话,就会失效了,所以必须提供另外一个setOnAdapterScrollListener,然后再传入一个OnScrollListener,然后在每个方法中进行回调就好了,因为考虑到以后可能会扩展其他的接口方法,所以这里新写了一个接口(为了以后扩展时原来的代码不会被影响,推荐使用OnAdapterScrollSampleListener这个实现类来代替OnAdapterScrollListener这个接口,OnAdapterScrollSampleListener这个类只是对OnAdapterScrollListener的所有方法进行了空实现)。
然后我们编写一个MyAdapter继承ABaseAdapter,然后,在getView()方法中,需要显示头像的时候调用如下方法:
// 如果在滚动(从内存中查找,找不到也不进行网络请求)
ImageLoader.getInstances().displayImage(headUrl, headIv, null, R.drawable.default_head, isScrolling());
看到木有?
1. displayImage()方法发生了改变,多了最后一个参数isOnlyMemory这个参数,表示是否只是在内存缓存中找这张图片,如果没有就不再继续找下去了(displayImage原来的方法我还留着,所以不会影响之前的代码)。
2. 调用了isScrolling()方法,作为参数isOnlyMemory的值,表示,如果正在滚动的话,就只在缓存中找这张图片。
这样,运行原来的代码试试吧,是不是效率快了一些?
[Android]ListView的Adapter.getView()方法中延迟加载图片的优化相关推荐
- android电脑文件列表不刷新,Android 利用RecyclerView.Adapter刷新列表中的单个view问题...
首先使用RecyclerView的adapter继承:RecyclerView.Adapter public class OrderListAdapter extends RecyclerView.A ...
- Android listview与adapter用法
2019独角兽企业重金招聘Python工程师标准>>> 一个ListView通常有两个职责. (1)将数据填充到布局. (2)处理用户的选择点击等操作. 第一点很好理解,ListVi ...
- Android listView 去掉header和footer中的分割线
Android listView 去掉header和footer中的分割线 方法一: 在listView中加上android:headerDividersEnabled="false&quo ...
- Android ListView反复调用getView和getCount
最近做项目发现一个界面当有ListView是,getView和getCount中的log被疯狂调用.一个5个Item的ListView,getView竟然会被反复调用7组.尤其是当ItemView中需 ...
- Android listview和adapter
ListView 和 Adapter的关系: 就是将ListView绑定的界面中的数据与adapter相适配 MainActivity.java package com.example.listvie ...
- Android源码—为什么onResume方法中不可以获取View宽高
前言 有一个经典的问题,我们在Activity的onCreate中可以获取View的宽高吗?onResume中呢? 对于这类八股问题,只要看过都能很容易得出答案:不能. 紧跟着追问一个,那为什么Vie ...
- 【Android FFMPEG 开发】FFMPEG 方法中指针类型参数说明 ( 一维指针类型参数 | 二维指针类型参数 )
文章目录 I . 一维指针类型参数 II . 二维指针类型参数 I . 一维指针类型参数 1 . 音视频流数据包获取 : //读取数据包AVPacket *avPacket = av_packet_a ...
- android 之自定义适配器(重写的getView()方法中convertView元素的妙用)一个实例
实现效果: 主要还是ListView的优化: 基本思路: <1>使用自定义适配器完成操作 <2>将listView进行优化处理 /* //ListView完成了重用条目的优化 ...
- Android ListView重写Adapter
在很多项目中都会用到ListView,但基本都需要进行重写Adapter,但每次都是会找好半天,写在这儿方便以后copy~~ xml定义一个ListView: <LinearLayout xml ...
最新文章
- 如何跟面试公司谈论薪资?
- 前端工程师和设计师必读文章推荐【系列三十六】
- 【转】Linux终端下 dstat 监控工具
- 如何解决Binder泄漏问题
- spring揭秘_被问到了! Spring 和 Spring Boot 之间到底有啥区别?
- 基于spi FLASH的嵌入式文件系统 littlefs(转)
- Swaps and Inversions hdu多校训练第二场 树状数组求逆序数+离散化
- 基于单片机智能交通灯控制系统设计外文文献_1000多套机械专业毕业设计免费分享(论文+DWG图纸+外文翻译+文献综述+开题报告+答辩) 友图网...
- 台达DOP-B触摸屏通过MODBUS RTU通讯4台台达M变频器.含触摸屏程序,接线图和变频器参数设定
- 智能创新引导工具软件——工作量分配和里程碑安排
- Python中filter筛选函数匿名参数问题
- 无意听到的歌, 心理很难受..
- 华为鸿蒙第一期公测,华为鸿蒙开启第二轮公测,新增7款机型,有你的吗?
- 公开招标,邀请招标,竞争性谈判,询价采购之间的区别
- Anti-Roll Bar -- 防倾杆
- cv曲线面积的意义_【CV现状-3.1】图像分割
- 100 道常见 Hadoop 面试题及答案解析
- Ultimaker对比Makerbot Replicator:好的不是一点点
- python re正则表达式提取含有某些关键词的句子,findall()查找含有关键词的句子
- 推荐个swf转gif工具“GifCam”
热门文章
- SQL查询语句精华总结
- ScheduledExecutorService线程调度的使用
- java多线程创建一个简单的案例
- Disconnected from the target VM, address:xxxx 或者 Process finished with exit code 1 终极解决办法 idea
- jmeter 聚合报告说明_jmeter之聚合报告
- 取枚举的参数c语言,求解:如何获得enum类型中枚举值的数量
- CSS 奇技淫巧:动态高度过渡动画
- 前端JavaScript 常见的报错及异常捕获与处理方法
- 前端开发者正在被迫成为全栈开发人员
- ctb伺服驱动器说明书_安川伺服驱动器SGDV报警原因及处理措施