Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> 優化Android平板上的GridView視圖緩存示例

優化Android平板上的GridView視圖緩存示例

編輯:Android開發實例

      最近在做android平板上的開發,其中涉及到高分辨率之下使用GridView的性能問題。在Android手機軟件開發中,如果在ListView或者GridView上使用大數量Item,很多人都會想到ViewHolder......沒錯,ViewHolder非常適合用在ListView或者每行小於4個Item的GridView。但是如果是高分辨率的設備(android平板甚至android電視),每行包含4個以上Item的話,即使用了ViewHolder也依然卡。

      如下圖,每行9個Item,而且每個Item的圖片都是從網絡動態下載的,這時就比較考驗GridView視圖的優化了。

      本文提出的優化方法是:在getView()構建一個View列表(List<View>),把最近構建的View存起來,回退時直接從View列表中讀取,而不是動態構建。使用這種方法有2個好處:

1.快速讀取過去的Item;

2.直接保存View而不是Bitmap,避免了ImageView.setImageBitmaps()帶來的延時。

當然壞處就是浪費內存,所以要設定一個上限,超過了就刪掉最老的Item。
先來看看這種方法與ViewHolder的性能對比:


100個Item往下滾到的三組數據對比,如上圖:
“CacheAdapter 緩存50個Item”跟ViewHolderAdapter的速度很接近,由於CacheAdapter有緩存,所以會有1~2次快速讀取Item(10~20個)的情況,而ViewHolder的每次讀取Item速度比較平均。
“CacheAdapter 緩存75個Item”只在第一次往下滾動時消耗較長時間,第二次用了緩存的Item,所以速度快了很多。

 

 

100個Item往上滾到的三組數據對比,如上圖:

“CacheAdapter 緩存50個Item”比ViewHolderAdapter的速度略快,“CacheAdapter 緩存75個Item”依然是最快的。
總結:“CacheAdapter 緩存50個Item”速度與HolderView略快,讀取最近的Item速度最快,緩存的Item越多速度越快。“CacheAdapter 緩存75個Item”占用內存最少,這是由於一部分圖片下載失敗,保存的Item的圖片為空,實際上是緩存越多Item占用的內存越多。

PS:這裡用到異步讀取網絡圖片,成功下載的就占用較多內存,下載失敗就占用較少內存,所以內存占用情況並不是一個時刻的絕對值,占用內存只用於參考.....

本文程序源碼可以到http://www.rayfile.com/zh-cn/files/5ebf5666-958a-11e0-99ec-0015c55db73d/這裡下載。

CacheAdapter.java是實現緩存Item的自定義Adapter,源碼如下:

  1. /** 
  2.  * 使用列表緩存過去的Item 
  3.  * @author hellogv 
  4.  *  
  5.  */ 
  6. public class CacheAdapter extends BaseAdapter { 
  7.  
  8.     public class Item { 
  9.         public String itemImageURL; 
  10.         public String itemTitle; 
  11.         public Item(String itemImageURL, String itemTitle) { 
  12.             this.itemImageURL = itemImageURL; 
  13.             this.itemTitle = itemTitle; 
  14.         } 
  15.     } 
  16.  
  17.     private Context mContext; 
  18.     private ArrayList<Item> mItems = new ArrayList<Item>(); 
  19.     LayoutInflater inflater; 
  20.     public CacheAdapter(Context c) { 
  21.         mContext = c; 
  22.         inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  23.     } 
  24.  
  25.     public void addItem(String itemImageURL, String itemTitle) { 
  26.         mItems.add(new Item(itemImageURL, itemTitle)); 
  27.     } 
  28.  
  29.     public int getCount() { 
  30.         return mItems.size(); 
  31.     } 
  32.  
  33.     public Item getItem(int position) { 
  34.         return mItems.get(position); 
  35.     } 
  36.  
  37.     public long getItemId(int position) { 
  38.         return position; 
  39.     } 
  40.      
  41.     List<Integer> lstPosition=new ArrayList<Integer>(); 
  42.     List<View> lstView=new ArrayList<View>(); 
  43.      
  44.     List<Integer> lstTimes= new ArrayList<Integer>(); 
  45.     long startTime=0; 
  46.     public View getView(int position, View convertView, ViewGroup parent) { 
  47.         startTime=System.nanoTime(); 
  48.          
  49.         if (lstPosition.contains(position) == false) { 
  50.             if(lstPosition.size()>75)//這裡設置緩存的Item數量 
  51.             { 
  52.                 lstPosition.remove(0);//刪除第一項 
  53.                 lstView.remove(0);//刪除第一項 
  54.             } 
  55.             convertView = inflater.inflate(R.layout.item, null); 
  56.             TextView text = (TextView) convertView.findViewById(R.id.itemText); 
  57.             ImageView icon = (ImageView) convertView.findViewById(R.id.itemImage); 
  58.             text.setText(mItems.get(position).itemTitle); 
  59.             new AsyncLoadImage().execute(new Object[] { icon,mItems.get(position).itemImageURL }); 
  60.              
  61.             lstPosition.add(position);//添加最新項 
  62.             lstView.add(convertView);//添加最新項 
  63.         } else 
  64.         { 
  65.             convertView = lstView.get(lstPosition.indexOf(position)); 
  66.         } 
  67.          
  68.         int endTime=(int) (System.nanoTime()-startTime); 
  69.         lstTimes.add(endTime); 
  70.         if(lstTimes.size()==10) 
  71.         { 
  72.             int total=0; 
  73.             for(int i=0;i<lstTimes.size();i++) 
  74.                 total=total+lstTimes.get(i); 
  75.      
  76.             Log.e("10個所花的時間:" +total/1000 +" μs", 
  77.                     "所用內存:"+Runtime.getRuntime().totalMemory()/1024 +" KB"); 
  78.             lstTimes.clear(); 
  79.         } 
  80.          
  81.         return convertView; 
  82.     } 
  83.  
  84.     /** 
  85.      * 異步讀取網絡圖片 
  86.      * @author hellogv 
  87.      */ 
  88.     class AsyncLoadImage extends AsyncTask<Object, Object, Void> { 
  89.         @Override 
  90.         protected Void doInBackground(Object... params) { 
  91.  
  92.             try { 
  93.                 ImageView imageView=(ImageView) params[0]; 
  94.                 String url=(String) params[1]; 
  95.                 Bitmap bitmap = getBitmapByUrl(url); 
  96.                 publishProgress(new Object[] {imageView, bitmap}); 
  97.             } catch (MalformedURLException e) { 
  98.                 Log.e("error",e.getMessage()); 
  99.                 e.printStackTrace(); 
  100.             } catch (IOException e) { 
  101.                 Log.e("error",e.getMessage()); 
  102.                 e.printStackTrace(); 
  103.             } 
  104.             return null; 
  105.         } 
  106.  
  107.         protected void onProgressUpdate(Object... progress) { 
  108.             ImageView imageView = (ImageView) progress[0]; 
  109.             imageView.setImageBitmap((Bitmap) progress[1]);          
  110.         } 
  111.     } 
  112.  
  113.     static public Bitmap getBitmapByUrl(String urlString) 
  114.             throws MalformedURLException, IOException { 
  115.         URL url = new URL(urlString); 
  116.         URLConnection connection = url.openConnection(); 
  117.         connection.setConnectTimeout(25000); 
  118.         connection.setReadTimeout(90000); 
  119.         Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream()); 
  120.         return bitmap; 
  121.     } 

其中if(lstPosition.size()>75)是設置緩存的Item數量的關鍵地方,這裡緩存75個Item。

ViewHolderAdapter.java是實現ViewHolder加載Item的自定義Adapter,源碼如下:

  1. /** 
  2.  * 使用ViewHolder加載Item 
  3.  * @author hellogv 
  4.  *  
  5.  */ 
  6. public class ViewHolderAdapter extends BaseAdapter { 
  7.  
  8.     public class Item { 
  9.         public String itemImageURL; 
  10.         public String itemTitle; 
  11.  
  12.         public Item(String itemImageURL, String itemTitle) { 
  13.             this.itemImageURL = itemImageURL; 
  14.             this.itemTitle = itemTitle; 
  15.         } 
  16.     } 
  17.  
  18.     private Context mContext; 
  19.     private ArrayList<Item> mItems = new ArrayList<Item>(); 
  20.     LayoutInflater inflater; 
  21.     public ViewHolderAdapter(Context c) { 
  22.         mContext = c; 
  23.         inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  24.     } 
  25.  
  26.     public void addItem(String itemImageURL, String itemTitle) { 
  27.         mItems.add(new Item(itemImageURL, itemTitle)); 
  28.     } 
  29.      
  30.     public int getCount() { 
  31.         return mItems.size(); 
  32.     } 
  33.  
  34.     public Item getItem(int position) { 
  35.         return mItems.get(position); 
  36.     } 
  37.  
  38.     public long getItemId(int position) { 
  39.         return position; 
  40.     } 
  41.      
  42.     static class ViewHolder { 
  43.         TextView text; 
  44.         ImageView icon; 
  45.     } 
  46.      
  47.     List<Integer> lstTimes= new ArrayList<Integer>(); 
  48.     long startTime=0; 
  49.     public View getView(int position, View convertView, ViewGroup parent) { 
  50.         startTime=System.nanoTime(); 
  51.          
  52.         ViewHolder holder; 
  53.  
  54.         if (convertView == null) { 
  55.             convertView = inflater.inflate(R.layout.item, null); 
  56.             holder = new ViewHolder(); 
  57.             holder.text = (TextView) convertView.findViewById(R.id.itemText); 
  58.             holder.icon = (ImageView) convertView.findViewById(R.id.itemImage); 
  59.             convertView.setTag(holder); 
  60.         } else { 
  61.             holder = (ViewHolder) convertView.getTag(); 
  62.         } 
  63.         holder.text.setText(mItems.get(position).itemTitle); 
  64.         new AsyncLoadImage().execute(new Object[]{holder.icon,mItems.get(position).itemImageURL }); 
  65.          
  66.         int endTime=(int) (System.nanoTime()-startTime); 
  67.         lstTimes.add(endTime); 
  68.         if(lstTimes.size()==10) 
  69.         { 
  70.             int total=0; 
  71.             for(int i=0;i<lstTimes.size();i++) 
  72.                 total=total+lstTimes.get(i); 
  73.      
  74.             Log.e("10個所花的時間:" +total/1000 +" μs", 
  75.                     "所用內存:"+Runtime.getRuntime().totalMemory()/1024 +" KB"); 
  76.             lstTimes.clear(); 
  77.         } 
  78.          
  79.         return convertView; 
  80.     } 
  81.  
  82.     /** 
  83.      * 異步讀取網絡圖片 
  84.      * @author hellogv 
  85.      */ 
  86.     class AsyncLoadImage extends AsyncTask<Object, Object, Void> { 
  87.         @Override 
  88.         protected Void doInBackground(Object... params) { 
  89.  
  90.             try { 
  91.                 ImageView imageView=(ImageView) params[0]; 
  92.                 String url=(String) params[1]; 
  93.                 Bitmap bitmap = CacheAdapter.getBitmapByUrl(url); 
  94.                 publishProgress(new Object[] {imageView, bitmap}); 
  95.             } catch (MalformedURLException e) { 
  96.                 e.printStackTrace(); 
  97.             } catch (IOException e) { 
  98.                 e.printStackTrace(); 
  99.             } 
  100.             return null; 
  101.         } 
  102.  
  103.         protected void onProgressUpdate(Object... progress) { 
  104.             ImageView imageView = (ImageView) progress[0]; 
  105.             imageView.setImageBitmap((Bitmap) progress[1]); 
  106.         } 
  107.     } 
  108.  

testPerformance.java是主程序,通過注釋符就可以分別測試CacheAdapter與ViewHolderAdapter的性能,源碼如下:

 

  1. public class testPerformance extends Activity { 
  2.     /** Called when the activity is first created. */ 
  3.     @Override 
  4.     public void onCreate(Bundle savedInstanceState) { 
  5.         super.onCreate(savedInstanceState); 
  6.         setContentView(R.layout.main); 
  7.         this.setTitle("android平板上的GridView視圖緩存優化-----hellogv"); 
  8.         GridView gridview = (GridView) findViewById(R.id.gridview); 
  9.         CacheAdapter adapter=new CacheAdapter(this); 
  10.         // ViewHolderAdapter adapter=new ViewHolderAdapter(this); 
  11.         
  12.         gridview.setAdapter(adapter); 
  13.         String urlImage="";//請自己選擇網絡上的靜態圖片 
  14.          
  15.         for(int i=0;i<100;i++) 
  16.         { 
  17.             adapter.addItem(urlImage, "第"+i+"項"); 
  18.         } 
  19.          
  20.     } 

 

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