ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的

所以这里就需要把这些信息利用多线程实现异步加载

实现这样功能的类

  1. public class AsyncImageLoader {
  2. private HashMap<String, SoftReference<Drawable>> imageCache;
  3. public AsyncImageLoader() {
  4. imageCache = new HashMap<String, SoftReference<Drawable>>();
  5. }
  6. public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
  7. if (imageCache.containsKey(imageUrl)) {
  8. SoftReference<Drawable> softReference = imageCache.get(imageUrl);
  9. Drawable drawable = softReference.get();
  10. if (drawable != null) {
  11. return drawable;
  12. }
  13. }
  14. final Handler handler = new Handler() {
  15. @Override
  16. public void handleMessage(Message message) {
  17. imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
  18. }
  19. };
  20. new Thread() {
  21. @Override
  22. public void run() {
  23. Drawable drawable = loadImageFromUrl(imageUrl);
  24. imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
  25. Message message = handler.obtainMessage(0, drawable);
  26. handler.sendMessage(message);
  27. }
  28. }.start();
  29. return null;
  30. }
  31. public static Drawable loadImageFromUrl(String url) {
  32. // ...
  33. }
  34. public interface ImageCallback {
  35. public void imageLoaded(Drawable imageDrawable, String imageUrl);
  36. }
  37. }

注意这里使用了 SoftReference来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。它这样工作:

·         调用 loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的 ImageCallback接口

·         如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过 ImageCallback回调

·         如果图片确实存在于缓存中,就会马上返回,不会回调 ImageCallback

然后我们还可以根据09google I/0开发者大会提到的方式来继续优化Adapter 使用ViewHolder来减少一些比较费时的操作,譬如inflate XML 和 findViewById()等操作

  1. public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {
  2. private ListView listView;
  3. private AsyncImageLoader asyncImageLoader;
  4. public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
  5. super(activity, 0, imageAndTexts);
  6. this.listView = listView;
  7. asyncImageLoader = new AsyncImageLoader();
  8. }
  9. @Override
  10. public View getView(int position, View convertView, ViewGroup parent) {
  11. Activity activity = (Activity) getContext();
  12. // Inflate the views from XML
  13. View rowView = convertView;
  14. ViewCache viewCache;
  15. if (rowView == null) {
  16. LayoutInflater inflater = activity.getLayoutInflater();
  17. rowView = inflater.inflate(R.layout.image_and_text_row, null);
  18. viewCache = new ViewCache(rowView);
  19. rowView.setTag(viewCache);
  20. } else {
  21. viewCache = (ViewCache) rowView.getTag();
  22. }
  23. ImageAndText imageAndText = getItem(position);
  24. // Load the image and set it on the ImageView
  25. String imageUrl = imageAndText.getImageUrl();
  26. ImageView imageView = viewCache.getImageView();
  27. imageView.setTag(imageUrl);
  28. Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {
  29. public void imageLoaded(Drawable imageDrawable, String imageUrl) {
  30. ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
  31. if (imageViewByTag != null) {
  32. imageViewByTag.setImageDrawable(imageDrawable);
  33. }
  34. }
  35. });
  36. imageView.setImageDrawable(cachedImage);
  37. // Set the text on the TextView
  38. TextView textView = viewCache.getTextView();
  39. textView.setText(imageAndText.getText());
  40. return rowView;
  41. }
  42. }

这里我们没有加载完iamge之后直接设定到相应的ImageView上 ,而是通过Tag查找,这里我们重用的View 这里有个listView的引用来通过Tag查找 可见 CallBack的实现

  1. ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
  2. if (imageViewByTag != null) {
  3. imageViewByTag.setImageDrawable(imageDrawable);
  4. }

这里通过ViewCatch来减少了 findViewById的使用

  1. public class ViewCache {
  2. private View baseView;
  3. private TextView textView;
  4. private ImageView imageView;
  5. public ViewCache(View baseView) {
  6. this.baseView = baseView;
  7. }
  8. public TextView getTextView() {
  9. if (textView == null) {
  10. textView = (TextView) baseView.findViewById(R.id.text);
  11. }
  12. return titleView;
  13. }
  14. public ImageView getImageView() {
  15. if (imageView == null) {
  16. imageView = (ImageView) baseView.findViewById(R.id.image);
  17. }
  18. return imageView;
  19. }
  20. }

总结 :这里主要做了三点优化

  • 在单一线程里加载图片
  • 重用列表中行
  • 缓存行中的 View

转自:http://blog.csdn.net/wanglong0537/article/details/6334005

Android进阶:ListView性能优化异步加载图片 使滑动效果流畅的更多相关文章

  1. 【Android】ListView、RecyclerView异步加载图片引起错位问题

    今天在RecyclerView列表里遇到一个情况,它包含300条数据,每项包含一个图片,发现在首次载入时,由于本地没图,请求网络的时候:快速滑动导致了图片错位.闪烁的问题. 原理的话有一篇已经说的很清 ...

  2. ListView与GridView异步加载图片

    原理很简单,主要是用到了回调方法,下面是异步加载图片的类 <span style="font-size:16px;">package com.xxx.xxx; impo ...

  3. 又优化了一下 Android ListView 异步加载图片

    写这篇文章并不是教大家怎么样用listview异步加载图片,因为这样的文章在网上已经有很多了,比如这位仁兄写的就很好: http://www.iteye.com/topic/685986 我也是因为看 ...

  4. Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如L ...

  5. Android之ListView异步加载图片且仅显示可见子项中的图片

    折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整 ...

  6. Android的ListView异步加载图片时,错位、重复、闪烁问题的分析及解决方法

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图 ...

  7. Listview 异步加载图片之优化篇(有图有码有解释)

    在APP应用中,listview的异步加载图片方式能够带来很好的用户体验,同时也是考量程序性能的一个重要指标.关于listview的异步加载,网上其实很多示例了,中心思想都差不多,不过很多版本或是有b ...

  8. android Listview 软引用SoftReference异步加载图片

    首先说一下,android系统加载大量图片系统内存溢出的3中解决方法: (1)从网络或本地加载图片的时候,只加载缩略图.这个方法的确能够少占用不少内存,可是它的致命的缺点就是,因为加载的是缩略图,所以 ...

  9. Listview异步加载图片之优化篇

    在APP应用中,listview的异步加载图片方式能够带来很好的用户体验,同时也是考量程序性能的一个重要指标.关于listview的异步加载,网上其实很多示例了,中心思想都差不多,不过很多版本或是有b ...

随机推荐

  1. 数据结构C语言版--单链表的基本功能实现

    /* * 构造一个链式存储的线性表(当输入9999时,结束构造过程),然后输出该线性表 * 并统计该线性链表的长度 . *注:new和delete是C++的运算符 malloc和free是C++/C的 ...

  2. python 廖雪峰的官方网站

    https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014316119884678 ...

  3. ASP.NET Web API实现缓存的2种方式

    在ASP.NET Web API中实现缓存大致有2种思路.一种是通过ETag, 一种是通过类似ASP.NET MVC中的OutputCache. 通过ETag实现缓存 首先安装cachecow.ser ...

  4. SRS流媒体服务器安装配置

    SRS全称Simple RTMP Server,定位是运营级的互联网直播服务器集群,是一个非常简单就可以推送rtmp视频流的服务器. github主页:https://github.com/ossrs ...

  5. 使用lightProbe来模拟动态物体的照明shader

    VertexLit path中读取lightProbe烘焙信息: Shader "VertexLitProbe" { Properties { _MainTex ("Ba ...

  6. 【Zookeeper】源码分析之服务器(二)之ZooKeeperServer

    一.前言 前面阐述了服务器的总体框架,下面来分析服务器的所有父类ZooKeeperServer. 二.ZooKeeperServer源码分析 2.1 类的继承关系 public class ZooKe ...

  7. funny

    var life = { "work_hard","have_fun","make_history" };

  8. springMVC之mvc:interceptors拦截器的用法

    1.配置拦截器 在springMVC.xml配置文件增加: <mvc:interceptors> <!-- 日志拦截器 --> <mvc:interceptor> ...

  9. Apache学习---多进程处理模块(MPM)原理详解

    查看Apache的模式,可以使用httpd -V命令来查看: 1. prefork MPM prefork模式可以算是很古老但是非常稳定的Apache模式.Apache在启动之初,就预先fork一些子 ...

  10. ubuntu安装odbc及(mysql驱动)

    一.安装odbc apt-get install unixodbc 如果需要用到编译的头文件之类的 apt-get install unixodbc-dev 二.安装mysql驱动 apt-get i ...