android用戶界面編程技巧——如何使用Adapter

 首先我要說明的是這裏“android用戶編程技巧”系列的文章中所涉及的技術技巧以及講述方式不是我本人原創。這些技巧是來自2009年google開發者日 (Google Developer Day 2009)上,google公司一位負負責android系統framework層和瀏覽器開發的一位工程師(很抱歉沒有能記住她的名字)的技巧 ,因爲是在開發者大會上演講是分享的,所以很多人稱之爲官方的技巧。 當然演講的具體內容大家可以通過網絡輕易得到我也會在後期的文章中給出演講視頻的地址和文檔下載地址。我這這裏寫出來主要是想這樣的技術人跟多的知 道和使用。過了一年的時間或許這些技巧中有些已經有待更新,那麼就讓我們一起在這裏討論吧。 

 重點說演講中的第一部分——如何使用Adapter。 
 ·
  •  adapter和listview以及數據源之間的關係 
listview相信是大家熟知的一種視圖控件了,那麼在Adapter相信大家也是一定不會陌生。正如這位是工程師說話Adapter是listview和數據源之間的中間人。 關係如圖所示。圖片是演講時所用ppt中的圖片。
android用戶界面編程技巧——如何使用Adapter - 琴絃jerry - 琴絃jerry
 
 adapte listview 數據源之間的關係圖
 
 當我們滑動listview的時候每一條數據進入可見區域的時候adapter的getView方法就會被調用,返回代表具體數據的視圖。那麼當我們的listview中有多條數 據的時候(一般都是有多條數據的),getView方法就會反覆多次的頻繁調用。這樣的listview就可以顯示很多數據,即成百上千條數據。 那麼顯而易見,由於getview方法是頻繁調用的我們應該經歷的在這個方法中儘可能少的產生對象,最大可能大的提高這個方法的工作效率。這樣我們的list的 更新速度才不至於太慢。
 
  •  剖析listview
 
 讓我們來虛擬一個listview 我們假設這個listview的可見區域中有7個listview,當我們用手指向上滑動一個item的時候,第一條數據就離開了可見區域。在 android系統上,爲了有效的使用java機制,設立了回收區域。那麼離開可見區域的數據就進入了會回收區域,以便於以後再次使用。adpater怎麼會對應的 標記這個離開可見區域的數據項,adapter同時會生產第八個視圖的數據並顯示在可見區域。這個就完了listview的一次更新。 
 
  •  簡單示例 
 我們假設需要完成的listview的每一個數據視圖如圖所示:
android用戶界面編程技巧——如何使用Adapter - 琴絃jerry - 琴絃jerry
 
 示例佈局 它的佈局文件如下: 
<LinearLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”horizontal”>
<ImageView android:id=”@+id/icon”
android:layout_width=”48dip”
android:layout_height=”48dip” />
<TextView android:id=”@+id/text”
android:layout_gravity=”center_vertical”
android:layout_width=”0dip”
android:layout_weight=”1.0″
android:layout_height=”wrap_content” />
</LinearLayout>
  •  最簡單的方法: 

public View getView(int pos, View convertView,

ViewGroup parent){

View item = mInflater.inflate(R.layout.list_item, null);

((TextView) item.findViewById(R.id.text)).

setText(DATA[pos]);

((ImageView) item.findViewButId(R.id.icon)).

setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);

return item;

}
 
inflate方法每次調用getview方法的時候都會調用,但是我們發現 每一個view都是同樣的操作。最主要的是,正如我們前面所說當,一個item視圖從可見區 域被滑動到不可見區域之後,它會進入會區域,但我們再次讓這個item進入可見區域的時候我們完全沒有必須有再次調用 inflate方法來展開視圖,所以這個 部分,我們可以利用converView來做一個判斷,當converView是null時,也就是回收區域中麼有我們要顯示的視圖的時候我們纔去調用inflate方法展開視圖 佈局。這樣我們就可以對代碼進行簡單有效的優化。 

  • 利用convertView回收視圖, 效率提高 200% 

public View getView(int pos, View convertView,
ViewGroup parent){
if (convertView == null) {
convertView = mInflater.inflate(
R.layout.list_item, null);
}

((TextView) convertView.findViewById(R.id.text)).
setText(DATA[pos]);
((ImageView) convertView.findViewButId(R.id.icon)).
setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
相同,我們會發現findviewbyid這裏的計劃代碼也是每次都要調用,我們是不是可以有一個什麼方法,讓這些操作也像前面的一樣回收起來呢。這個時候我們 考慮使用viewholder模式。我們首先寫一個靜態的類,將每一個item的子視圖,一個圖片視圖和一個文本視圖緩存或者說是回收在這個靜態類中,這樣我們 就可以節省一些執行findviewbyid方法的時間。這樣我們又一次可以優化代碼。 

  • 利用ViewHolder模式,效率再次調高50% 
 ViewHolder靜態類: 

static class ViewHolder {
TextView text;
ImageView icon;
}
getview方法代碼如下:
public View getView(int pos, View convertView, ViewGroup parent){
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text));
holder.icon = (ImageView) convertView.findViewButId(R.id.icon));
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[pos]);
holder.icon.setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
 
 最後呢,這位工程師對這三種方式進行了一個更新數據的比較,用一般的方法每秒更新8個frame,採用回收機制的方法是每秒27個frame,採用ViewHolder 模式方法每秒36個frame。 
 更新效率比較圖:
android用戶界面編程技巧——如何使用Adapter - 琴絃jerry - 琴絃jerry
 
 三種方式更新效率比較 最後,着這次演講中一個設計了5個模塊的編程技巧,如下:
 · Adapter的使用 
 · 圖像和背景 
 · 更新請求 
 · 視圖和佈局
 · 內存分配 
後續我會陸續將其他部分在這裏發佈,再次申明這些方法是09年google開發者大會分享的,我不知道爲什麼這些方法按理來說應該早爲我們中國開發者所熟 知,可是我在很多社區中看多有很多朋友還在找出找這些問題的答案。因此我再次將這些技巧整理髮布出來,希望更多的朋友在使用搜索引擎的時候可以找到 這些技巧。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章