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(0drawable);  
  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.  
Java代码 
  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(0drawable);  
  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()等操作

      

  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, 0imageAndTexts);  
  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.   
Java代码 
  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, 0imageAndTexts);  
  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的实现

 

     

  1. ImageView imageViewByTag (ImageView) listView.findViewWithTag(imageUrl);  
  2.                if (imageViewByTag != null 
  3.                    imageViewByTag.setImageDrawable(imageDrawable);  
  4.                 
C-sharp代码 
  1. ImageView imageViewByTag (ImageView) listView.findViewWithTag(imageUrl);  
  2.                if (imageViewByTag != null 
  3.                    imageViewByTag.setImageDrawable(imageDrawable);  
  4.                 

 

 

     这里通过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.   
C-sharp代码 
  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
附:不错的异步加载网络图片代码
private void queuePhoto(String url, Activity activity,ImageView imageView) 
      {
          // This ImageView may be usedfor other images before. So there may be
          // some old tasks in thequeue. We need to discard them.

          photosQueue.Clean(imageView);
          PhotoToLoad p = newPhotoToLoad(url, imageView);

          synchronized(photosQueue.photosToLoad) 
          {
              photosQueue.photosToLoad.push(p);
              photosQueue.photosToLoad.notifyAll();
          }

          // start thread if it's notstarted yet
          if(photoLoaderThread.getState() == Thread.State.NEW)
              photoLoaderThread.start();
      }

      publicBitmap getBitmap(String url) 
      {
          try
          {
              // I identify images by hashcode. Not a perfectsolution, good for the
              // demo.
              String filename =String.valueOf(url.hashCode());
              File f = new File(cacheDir, filename);

              // from SD cache
              Bitmap b = decodeFile(f);
              if (b != null)
                  returnb;

              // from web
              try {
                  Bitmapbitmap = null;        
                  if(!url.equals("")){
                  InputStreamis = new URL(url).openStream();
                  OutputStream os = new FileOutputStream(f);
                  Utils.CopyStream(is, os);
                  os.close();
                  bitmap =decodeFile(f);
                  }
                  returnbitmap;
             
              catch (Exception ex) 
              {
                  ex.printStackTrace();
              return null;
              }
          }
          catch(Exception e)
          {
              e.printStackTrace();

              return null;    
          }
      }

     
      privateBitmap decodeFile(File f){
          Bitmap b = null;
          try {

              useThisBitmap = null;
              //Decode image size
              BitmapFactory.Options o = newBitmapFactory.Options();
              o.inJustDecodeBounds = true;
              final int IMAGE_MAX_SIZE = 70;
              BitmapFactory.decodeStream(newFileInputStream(f), null, o);
              int scale = 2;
              if (o.outHeight > IMAGE_MAX_SIZE|| o.outWidth > IMAGE_MAX_SIZE) {
                  scale = 2 ^(int) Math.ceil(Math.log(IMAGE_MAX_SIZE / (double)Math.max(o.outHeight, o.outWidth)) / Math.log(0.5));
              }

              //Decode with inSampleSize
              BitmapFactory.Options o2 = newBitmapFactory.Options();

              o2.inSampleSize = scale;
              b = BitmapFactory.decodeStream(newFileInputStream(f), null, o2);
              useThisBitmap = b;

         
          catch (FileNotFoundExceptione) {
          }
          catch(Exception e)
          {
              e.printStackTrace();
          }
          finally
          {
              System.gc();
          }
          return useThisBitmap;
      }


      // Taskfor the queue
      privateclass PhotoToLoad 
      {
          public String url;
          public ImageViewimageView;

          public PhotoToLoad(String u,ImageView i) {
              url = u;
              imageView = i;
          }
      }

      privatePhotosQueue photosQueue = new PhotosQueue();



      //stores list of photos to download
      privateclass PhotosQueue 
      {
          privateStack<PhotoToLoad> photosToLoad = newStack<PhotoToLoad>();
          // removes all instances ofthis ImageView
          private void Clean(ImageViewimage) 
          {
              for (int j = 0; j <photosToLoad.size();) 
              {
                  if(photosToLoad.get(j).imageView == image)
                      photosToLoad.remove(j);
                  else
                      ++j;
              }
          }
      }

      privateclass PhotosLoader extends Thread 
      {
          public voidrun() 
          {
              try 
              {
                  while(true) 
                  {
                      // thread waits until thereare any images to load in the
                      // queue
                      if(photosQueue.photosToLoad.size() == 0)
                          synchronized (photosQueue.photosToLoad) {
                              photosQueue.photosToLoad.wait();
                          }
                      if(photosQueue.photosToLoad.size() != 0) {
                          PhotoToLoad photoToLoad;
                          synchronized (photosQueue.photosToLoad) {
                              photoToLoad= photosQueue.photosToLoad.pop();
                          }
                          Bitmap bmp = getBitmap(photoToLoad.url);
                          cache.put(photoToLoad.url, bmp);
                          if (((String)photoToLoad.imageView.getTag())
                                  .equals(photoToLoad.url)){
                              BitmapDisplayer bd = newBitmapDisplayer(bmp,
                                      photoToLoad.imageView);
                              Activity a= (Activity) photoToLoad.imageView
                                      .getContext();
                              a.runOnUiThread(bd);
                          }
                      }
                      if(Thread.interrupted())
                          break;
                  }
              } catch (InterruptedException e) {
                  // allowthread to exit
              }
          }
      }

      privatePhotosLoader photoLoaderThread = new PhotosLoader();

      // Usedto display bitmap in the UI thread
      privateclass BitmapDisplayer implements Runnable 
      {
          private Bitmap bitmap;
          private ImageViewimageView;

          private BitmapDisplayer(Bitmapb, ImageView i) 
          {
              bitmap = b;
              imageView = i;
          }

          public voidrun() 
          {
              if (bitmap != null)
                  imageView.setImageBitmap(bitmap);
          }
      }

      publicvoid stopThread() 
      {
          photoLoaderThread.interrupt();
      }

      publicvoid clearCache() 
      {
          cache.clear();
          File[] files =cacheDir.listFiles();
          for (File f : files)
              f.delete();
      }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值