ListView是一种可以显示一系列项目并能进行滚动显示的View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的
所以这里就需要把这些信息利用多线程实现异步加载
实现这样功能的类
- publicclassAsyncImageLoader{
- privateHashMap<String,SoftReference<Drawable>>imageCache;
- publicAsyncImageLoader(){
- imageCache=newHashMap<String,SoftReference<Drawable>>();
- }
- publicDrawableloadDrawable(finalStringimageUrl,finalImageCallbackimageCallback){
- if(imageCache.containsKey(imageUrl)){
- SoftReference<Drawable>softReference=imageCache.get(imageUrl);
- Drawabledrawable=softReference.get();
- if(drawable!=null){
- returndrawable;
- }
- }
- finalHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemessage){
- imageCallback.imageLoaded((Drawable)message.obj,imageUrl);
- }
- };
- newThread(){
- @Override
- publicvoidrun(){
- Drawabledrawable=loadImageFromUrl(imageUrl);
- imageCache.put(imageUrl,newSoftReference<Drawable>(drawable));
- Messagemessage=handler.obtainMessage(0,drawable);
- handler.sendMessage(message);
- }
- }.start();
- returnnull;
- }
- publicstaticDrawableloadImageFromUrl(Stringurl){
- //...
- }
- publicinterfaceImageCallback{
- publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl);
- }
- }
注意这里使用了SoftReference来缓存图片,允许GC在需要的时候可以对缓存中的图片进行清理。它这样工作:
·调用loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的ImageCallback接口
·如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过ImageCallback回调
·如果图片确实存在于缓存中,就会马上返回,不会回调ImageCallback
然后我们还可以根据09google I/0开发者大会提到的方式来继续优化Adapter 使用ViewHolder来减少一些比较费时的操作,譬如inflate XML 和 findViewById()等操作
- publicclassImageAndTextListAdapterextendsArrayAdapter<ImageAndText>{
- privateListViewlistView;
- privateAsyncImageLoaderasyncImageLoader;
- publicImageAndTextListAdapter(Activityactivity,List<ImageAndText>imageAndTexts,ListViewlistView){
- super(activity,0,imageAndTexts);
- this.listView=listView;
- asyncImageLoader=newAsyncImageLoader();
- }
- @Override
- publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
- Activityactivity=(Activity)getContext();
- //InflatetheviewsfromXML
- ViewrowView=convertView;
- ViewCacheviewCache;
- if(rowView==null){
- LayoutInflaterinflater=activity.getLayoutInflater();
- rowView=inflater.inflate(R.layout.image_and_text_row,null);
- viewCache=newViewCache(rowView);
- rowView.setTag(viewCache);
- }else{
- viewCache=(ViewCache)rowView.getTag();
- }
- ImageAndTextimageAndText=getItem(position);
- //LoadtheimageandsetitontheImageView
- StringimageUrl=imageAndText.getImageUrl();
- ImageViewimageView=viewCache.getImageView();
- imageView.setTag(imageUrl);
- DrawablecachedImage=asyncImageLoader.loadDrawable(imageUrl,newImageCallback(){
- publicvoidimageLoaded(DrawableimageDrawable,StringimageUrl){
- ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);
- if(imageViewByTag!=null){
- imageViewByTag.setImageDrawable(imageDrawable);
- }
- }
- });
- imageView.setImageDrawable(cachedImage);
- //SetthetextontheTextView
- TextViewtextView=viewCache.getTextView();
- textView.setText(imageAndText.getText());
- returnrowView;
- }
- }
这里我们没有加载完iamge之后直接设定到相应的ImageView上 ,而是通过Tag查找,这里我们重用的View 这里有个listView的引用来通过Tag查找 可见 CallBack的实现
- ImageViewimageViewByTag=(ImageView)listView.findViewWithTag(imageUrl);
- if(imageViewByTag!=null){
- imageViewByTag.setImageDrawable(imageDrawable);
- }
这里通过ViewCatch来减少了 findViewById的使用
- publicclassViewCache{
- privateViewbaseView;
- privateTextViewtextView;
- privateImageViewimageView;
- publicViewCache(ViewbaseView){
- this.baseView=baseView;
- }
- publicTextViewgetTextView(){
- if(textView==null){
- textView=(TextView)baseView.findViewById(R.id.text);
- }
- returntitleView;
- }
- publicImageViewgetImageView(){
- if(imageView==null){
- imageView=(ImageView)baseView.findViewById(R.id.image);
- }
- returnimageView;
- }
- }
总结:这里主要做了三点优化
- 在单一线程里加载图片
- 重用列表中行
- 缓存行中的View