Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android進階:ListView性能優化異步加載圖片 使滑動效果流暢

Android進階:ListView性能優化異步加載圖片 使滑動效果流暢

編輯:Android開發實例

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(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()等操作

       

  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的實現

 

   

  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. }  

 

     總結 :這裡主要做了三點優化

 

 

  • 在單一線程裡加載圖片
  •   重用列表中行
  • 緩存行中的 View

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved