当前位置: 代码迷 >> Android >> Android进阶:ListView性能优化异步加载图片 使滑动成效流畅
  详细解决方案

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

热度:55   发布时间:2016-05-01 18:32:20.0
Android进阶:ListView性能优化异步加载图片 使滑动效果流畅

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

?

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

?

实现这样功能的类

?

?

view plaincopy to clipboardprint?
  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. }??

?

?

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

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

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

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

?

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

??????

view plaincopy to clipboardprint?
  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. }???

?

?

?

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

?

?????

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

?

?

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

?

????

view plaincopy to clipboardprint?
  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. }???

?

?

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

?

?

  • 在单一线程里加载图片
  • ? 重用列表中行
  • 缓存行中的 View
  相关解决方案