0
点赞
收藏
分享

微信扫一扫

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


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

 

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

 

实现这样功能的类

1. public class
2. private
3.    
4. public
5. new
6.     }  
7.    
8. public Drawable loadDrawable(final String imageUrl, final
9. if
10.             SoftReference<Drawable> softReference = imageCache.get(imageUrl);  
11.             Drawable drawable = softReference.get();  
12. if (drawable != null) {   
13. return
14.             }  
15.         }  
16. final Handler handler = new
17. @Override
18. public void
19.                 imageCallback.imageLoaded((Drawable) message.obj, imageUrl);  
20.             }  
21.         };  
22. new
23. @Override
24. public void
25.                 Drawable drawable = loadImageFromUrl(imageUrl);  
26. new
27. 0, drawable);   
28.                 handler.sendMessage(message);  
29.             }  
30.         }.start();  
31. return null;   
32.     }  
33.    
34. public static
35. // ... 
36.     }  
37.    
38. public interface
39. public void
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
2.    
3. private
4. private
5.    
6. public
7. super(activity, 0, imageAndTexts);   
8. this.listView = listView;   
9. new
10.     }  
11.    
12. @Override
13. public View getView(int
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. null);   
22. new
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. new
34. public void
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
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.                }



 

 

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

 

    




1. public class
2.    
3. private
4. private
5. private
6.    
7. public
8. this.baseView = baseView;   
9.     }  
10.    
11. public
12. if (textView == null) {   
13.             textView = (TextView) baseView.findViewById(R.id.text);  
14.         }  
15. return
16.     }  
17.    
18. public
19. if (imageView == null) {   
20.             imageView = (ImageView) baseView.findViewById(R.id.image);  
21.         }  
22. return
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
举报

相关推荐

0 条评论