ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的
?
所以这里就需要把这些信息利用多线程实现异步加载
?
实现这样功能的类
?
?
- 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()等操作
??????
- 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的实现
?
?????
- ImageView?imageViewByTag?=?(ImageView)?listView.findViewWithTag(imageUrl);??
- ???????????????if?(imageViewByTag?!=?null)?{??
- ???????????????????imageViewByTag.setImageDrawable(imageDrawable);??
- ???????????????}??
?
?
????? 这里通过ViewCatch来减少了 findViewById的使用
?
????
- 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