Android进阶:ListView性能优化异步加载图片 使滑动效果流畅

简介:

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

 

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

 

实现这样功能的类

 

 

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

public class AsyncImageLoader { private HashMap<String, SoftReference<Drawable>> imageCache; public AsyncImageLoader() { imageCache = new HashMap<String, SoftReference<Drawable>>(); } public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) { if (imageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = imageCache.get(imageUrl); Drawable drawable = softReference.get(); if (drawable != null) { return drawable; } } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageCallback.imageLoaded((Drawable) message.obj, imageUrl); } }; new Thread() { @Override public void run() { Drawable drawable = loadImageFromUrl(imageUrl); imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); Message message = handler.obtainMessage(0, drawable); handler.sendMessage(message); } }.start(); return null; } public static Drawable loadImageFromUrl(String url) { // ... } public interface ImageCallback { public void imageLoaded(Drawable imageDrawable, String imageUrl); }}

 

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

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

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

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

 

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

      

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

public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> { private ListView listView; private AsyncImageLoader asyncImageLoader; public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) { super(activity, 0, imageAndTexts); this.listView = listView; asyncImageLoader = new AsyncImageLoader(); } @Override public View getView(int position, View convertView, ViewGroup parent) { Activity activity = (Activity) getContext(); // Inflate the views from XML View rowView = convertView; ViewCache viewCache; if (rowView == null) { LayoutInflater inflater = activity.getLayoutInflater(); rowView = inflater.inflate(R.layout.image_and_text_row, null); viewCache = new ViewCache(rowView); rowView.setTag(viewCache); } else { viewCache = (ViewCache) rowView.getTag(); } ImageAndText imageAndText = getItem(position); // Load the image and set it on the ImageView String imageUrl = imageAndText.getImageUrl(); ImageView imageView = viewCache.getImageView(); imageView.setTag(imageUrl); Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() { public void imageLoaded(Drawable imageDrawable, String imageUrl) { ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl); if (imageViewByTag != null) { imageViewByTag.setImageDrawable(imageDrawable); } } }); imageView.setImageDrawable(cachedImage); // Set the text on the TextView TextView textView = viewCache.getTextView(); textView.setText(imageAndText.getText()); return rowView; }} 

 

 

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

 

     

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

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

 

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

 

    

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

public class ViewCache { private View baseView; private TextView textView; private ImageView imageView; public ViewCache(View baseView) { this.baseView = baseView; } public TextView getTextView() { if (textView == null) { textView = (TextView) baseView.findViewById(R.id.text); } return titleView; } public ImageView getImageView() { if (imageView == null) { imageView = (ImageView) baseView.findViewById(R.id.image); } return imageView; }} 

 

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

 

 

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

 

相关文章
|
23天前
|
缓存 监控 Android开发
安卓应用性能优化的实用策略
【4月更文挑战第2天】 在竞争激烈的应用市场中,一款应用的性能直接影响用户体验和市场表现。本文针对安卓平台,深入探讨了性能优化的关键要素,包括内存管理、代码效率、UI渲染和电池使用效率。通过分析常见的性能瓶颈,并提供针对性的解决策略,旨在帮助开发者构建更加流畅、高效的安卓应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
47 0
|
3月前
|
API Android开发 开发者
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
Android UI设计: 什么是RecyclerView?为什么它比ListView更好?
31 2
|
17天前
|
监控 API Android开发
构建高效安卓应用:探究Android 12中的新特性与性能优化
【4月更文挑战第8天】 在本文中,我们将深入探讨Android 12版本引入的几项关键技术及其对安卓应用性能提升的影响。不同于通常的功能介绍,我们专注于实际应用场景下的性能调优实践,以及开发者如何利用这些新特性来提高应用的响应速度和用户体验。文章将通过分析内存管理、应用启动时间、以及新的API等方面,为读者提供具体的技术实现路径和代码示例。
|
23天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
22 1
|
1月前
|
缓存 前端开发 Android开发
构建高效Android应用:从设计原则到性能优化
随着移动设备成为我们日常生活不可或缺的一部分,开发一个流畅且响应迅速的Android应用变得至关重要。本文将探讨如何通过遵循Android设计原则和实施细致的性能优化策略来构建高效的Android应用程序。我们将深入分析应用架构的选择、内存管理的要点以及UI设计的优化,旨在为开发人员提供一套实用的指导方针,帮助他们提升应用的整体性能和用户体验。
|
1月前
|
监控 Java Android开发
构建高效Android应用:从内存管理到性能优化
【2月更文挑战第30天】 在移动开发领域,打造一个流畅且响应迅速的Android应用是每个开发者追求的目标。本文将深入探讨如何通过有效的内存管理和细致的性能调优来提升应用效率。我们将从分析内存泄露的根本原因出发,讨论垃圾回收机制,并探索多种内存优化策略。接着,文中将介绍多线程编程的最佳实践和UI渲染的关键技巧。最后,我们将通过一系列实用的性能测试工具和方法,帮助开发者监控、定位并解决性能瓶颈。这些技术的综合运用,将指导读者构建出更快速、更稳定、用户体验更佳的Android应用。
|
1月前
|
Java 定位技术 Android开发
安卓应用性能优化实践
【2月更文挑战第26天】在竞争激烈的应用市场中,一个高效流畅的安卓应用是吸引和留住用户的关键。本文将深入探讨安卓应用性能优化的多个方面,包括内存管理、多线程处理、UI渲染效率以及电池使用优化。通过实例分析和最佳实践的分享,旨在帮助开发者构建更快、更稳定、更节能的安卓应用。
|
1月前
|
设计模式 缓存 Android开发
深入理解Android应用性能优化
【2月更文挑战第18天】在移动开发领域,应用性能是用户体验的关键因素之一。特别是对于安卓设备而言,由于硬件配置的多样性,确保应用在不同设备上都能流畅运行是一项挑战。本文将探讨Android应用的性能优化策略,包括内存管理、UI渲染、多线程处理以及电池效率等方面。通过实例和最佳实践,我们将展示如何诊断性能瓶颈,并提供解决方案来改善应用响应速度和稳定性。
|
3月前
|
存储 缓存 编解码
Android 性能优化: 解释Bitmap的优化策略。
Android 性能优化: 解释Bitmap的优化策略。
40 1