Android之ListView/GridView 最佳化

來源:互聯網
上載者:User

標籤:

一、效率最低的getView實現

我們知道,ListView和GridView的顯示都是通過Adapter的getView實現的。

ListView/GridView資料量較小時,我們的處理方式一般是這樣的(效率最低的一種方式)

1 public View getView(int position, View convertView, ViewGroup parent) {2      View item = mInflater.inflate(R.layout.list_item_icon_text, null);3      ((TextView) item.findViewById(R.id.text)).setText(DATA[position]);4      ((ImageView) item.findViewById(R.id.icon)).setImageBitmap(5      (position & 1) == 1 ? mIcon1 : mIcon2);6      return item;7 }

當資料量非常大時,這樣每一次getView都會去inflate布局,效率太差,這會讓我們的程式卡頓,滑動多了還會OOM。

 

二、利用Android已經提供了View緩衝機制實現ViewHolder模式——實現View共用

我們注意到getView的第二個參數convertView,這個是View緩衝機制的關鍵。簡單的說就兩點:

1.假設當前頁面我們有7個item,那麼前七次getView,這個convertView都是null

2.假設我們往上翻頁,現在Item8進入頁面,item1出頁面,此時Item8對應的getView中的convertView就是item1

 

利用這個View緩衝機制的特點,我們只需要將Item8的getView中convertView的資料由item1更新為item8即可。也就是說item8和item1就實現了View的共用。(本來嘛,item8和item1永遠不會在一個介面中一起出現,確實應該共用一些資源)

而這就是所謂的ViewHolder模式

        @Override        public View getView(int position, View convertView, ViewGroup arg2) {            List            Log.i("xerrard", "getView " + position + " " + convertView);            ViewHolder viewHolder = null;            if(convertView == null){                viewHolder = new ViewHolder();                convertView = inflater.inflate(R.layout.item, null);                viewHolder.image = (ImageView) convertView.findViewById(R.id.img);                viewHolder.text = (TextView) convertView.findViewById(R.id.txt);                convertView.setTag(viewHolder);            }else{                viewHolder = (ViewHolder) convertView.getTag();            }            viewHolder.image.setImageBitmap(imgs.get(position));            viewHolder.text.setText(texts.get(position));            return convertView;        }        class ViewHolder{            ImageView image;            TextView text;        }

 

 

三、ListView /GridView的非同步載入。

很多時候我們會需要再網上下載一些圖片來進行顯示,如果在主線程做下載的操作,這樣很可能會造成ANR,所以需要子線程來實現。(即使是本機存放區中的圖片,也建議用子線程來實現,本地IO操作有時也會造成ANR)

我們使用android中的AsyncTask來實現下載的操作

 1 /** 2  * Created by xuqiang on 15-12-16. 3  */ 4 public class ImageTask extends AsyncTask<String, Void, Bitmap> { 5     private ImageView iv; 6     String imgUrl; 7     public ImageTask(ImageView iv){ 8         this.iv = iv; 9     }10 11     @Override12     protected Bitmap doInBackground(String... param) {13         imgUrl = param[0];14         try {15             URL url = new URL(imgUrl);16             try {17                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();18                 InputStream in = conn.getInputStream();19                 Bitmap bitmap = BitmapFactory.decodeStream(in);20                 if(bitmap!=null){21                     return bitmap;22                 }23             } catch (IOException e) {24                 // TODO Auto-generated catch block25                 e.printStackTrace();26             }27         } catch (MalformedURLException e) {28             // TODO Auto-generated catch block29             e.printStackTrace();30         }31         return null;32     }33 34     @Override35     protected void onPostExecute(Bitmap result) {36         super.onPostExecute(result);37         if (result != null) {38             // 通過 tag 來防止圖片錯位39             if (iv.getTag() != null && iv.getTag().equals(imgUrl)) {40                 iv.setImageBitmap(result);41             }42         }43     }44 45     @Override46     protected void onPreExecute() {47         super.onPreExecute();48     }49 }

 

 

然後在getView中,我們只需要將原本對ViewHolder的操作,傳參數給ImageTask來處理

            ImageTask imageTask = new ImageTask(viewHolder.image,position);            imageTask.execute(imgUrls.get(position));

 

 四、ListView /GridView的非同步載入中的錯位問題解決

剛才我們知道,利用的android的View緩衝機制,我們可以使用ViewHolder最佳化ListView/GridView的效率。但是在非同步載入圖片的過程中,正是因為這個View共用的機制,會造成圖片錯位的情況。

這個問題,我們如何解決。

 

最簡單的解決方案就是網上說的,給 ImageView 設定一個 tag。

當 Item1 比 Item8 圖片下載的快時, 你滾下去使 Item8 可見,這時 ImageView 的 tag 被設成了

Item8 的 URL, 當 Item1 下載完時,由於 Item1 不可見現在的 tag 是 Item8 的 URL,所以不滿足條件,

雖然下載下來了但不會設定到 ImageView 上, tag 標識的永遠是可見 view 中圖片的 URL。

 我們最後將這個最終的改進方案寫下來

1.在主線程設定一個tag,

 1         @Override 2         public View getView(int position, View convertView, ViewGroup arg2) { 3             Log.i("xerrard", "getView " + position + " " + convertView); 4             ViewHolder viewHolder = null; 5             if(convertView == null){ 6                 viewHolder = new ViewHolder(); 7                 convertView = inflater.inflate(R.layout.item, null); 8                 viewHolder.image = (ImageView) convertView.findViewById(R.id.img); 9 10                 convertView.setTag(viewHolder);11             }else{12                 viewHolder = (ViewHolder) convertView.getTag();13             }14             viewHolder.image.setTag(imgUrls.get(position));15             ImageTask imageTask = new ImageTask(viewHolder.image);16             imageTask.execute(imgUrls.get(position));17             return convertView;18         }19         class ViewHolder{20             ImageView image;21         }22     }

2.在非同步ImageTask設定圖片的地方,判斷Tag,確認Tag沒有問題之後,再設定圖片

 1     @Override 2     protected void onPostExecute(Bitmap result) { 3         super.onPostExecute(result); 4         if (result != null) { 5             // 通過 tag 來防止圖片錯位 6             if (iv.getTag() != null && iv.getTag().equals(imgUrl)) { 7                 iv.setImageBitmap(result); 8             } 9         }10     }

 

Android之ListView/GridView 最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.