Android學習心得第五課
今天算是遇到了Android學習上面的一塊硬骨頭了,目前算是基本理解了,後面還是要時不時的來回顧一下,溫故而知新,下面就來回顧一下我今天學習的知識, 今天的知識點就一個那就是關於BaseAdapter,
上一節心得,我專門對資料介面卡進行了一個解釋,今天在慕課上看到一個比較好的圖,這裡分享一下。
從圖中我們可以看出為什麼需要資料介面卡這麼一個東西,因為資料來源是各種各樣的,但是listview它所接受的格式卻是固定的,這個時候我們就需要資料介面卡這麼一箇中間件,通過資料介面卡來將資料來源轉換成llistview所能夠接受的那種資料。
那麼BaseAdapter究竟希望它能夠幹什麼能,它主要是比較靈活,可以進行各種的改寫,listview有一個快取機制,如下圖:
通過這種機制我們可以大大的減輕記憶體的開銷。
下面我就來具體解釋一下關於BaseAdapter的事情。首先在這裡有一個小技巧,就是利用bean物件,將需要的資料先封裝起來。
public class MyBaseAdapter extends BaseAdapter {
// 對映資料
List<ItemBean> datalist;
private long mSumTime;
/*
* LayoutInflater這個類它的作用類似於findViewById()。
* 不同點是LayoutInflater是用來找res/layout/下的xml佈局檔案,並且例項化;
* 而findViewById()是找xml佈局檔案下的具體widget控制元件(如Button、TextView等)。
*/
private LayoutInflater mLayoutInflater;
public MyBaseAdapter(Context context, List<ItemBean> datalist) {
this.datalist = datalist;
mLayoutInflater = LayoutInflater.from(context);
}
// 獲取資料量
@Override
public int getCount() {
// TODO Auto-generated method stub
return datalist.size();
}
// 獲取對應ID的對應Item
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return datalist.get(position);
}
// 獲取對應的ID
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TODO Auto-generated method stub
//第一種方式(不加任何的優化)----------------------------------------------
//該函式的作用是為了將xml檔案轉換成View,這裡因為不涉及第二個引數,所以第二個引數為空
View view = mLayoutInflater.inflate(R.layout.item, null);
// 例項化控制元件
ImageView itemImage = (ImageView) view.findViewById(R.id.iv_image);
TextView itemTitle = (TextView) view.findViewById(R.id.tv_title);
TextView itemContent = (TextView) view.findViewById(R.id.tv_content);
// 去除bean物件
ItemBean bean = datalist.get(position);
// 設定控制元件的資料
itemImage.setImageResource(bean.itemImageResId);
itemTitle.setText(bean.itemTitle);
itemContent.setText(bean.itemContent);
return view;
第一種方法的一個巨大的缺點就在於,它每次呼叫getView函式的時候,都要新建一個View物件,這樣的話十分佔用資源,而且也沒有用到ListView的快取機制,這裡我們對其進行一個改進,下面放入getView的程式碼。
(2)第二種方式 利用 ListView 的快取機制進行改進
/*
* 第二種方式(加入優化)--第一種方法的弊端是每次呼叫getview的時候都要新建一個View物件
* 這種方法十分佔用記憶體,因為每次都需要新建一個View物件,這裡運用到了listview的快取機制,也就是
* 該函式的第二個引數convertView,通過使用它可以大大的減少記憶體的開銷 當listview物件非常複雜的時候這種方法十分有效。
*/
if (convertView == null) {
// 這種邏輯的意思就是當convertView為空時,說明是第一次呼叫,快取為空,所以將該佈局
// 轉換為View放入convertView中,當再次呼叫時不用再像第一種方法一樣每次都新建一個view
convertView = mLayoutInflater.inflate(R.layout.item, null);
}
ImageView itemImage = (ImageView) convertView
.findViewById(R.id.iv_image);
TextView itemTitle = (TextView)convertView
.findViewById(R.id.tv_title);
TextView itemContent = (TextView) convertView
.findViewById(R.id.tv_content);
ItemBean bean = datalist.get(position);
itemImage.setImageResource(bean.itemImageResId);
itemTitle.setText(bean.itemTitle);
itemContent.setText(bean.itemContent);
return convertView;
這裡和上式相比,利用convertView引數來避免了每次重複新建View物件,但是這種物件還沒達到最佳的優化,因為findViewById這個函式每次在執行的時候是需要遍歷整個檢視樹,當檢視樹比較複雜的時候,這個遍歷的時間將會相當的可觀。所以這裡可以用到Google提出的一個新的方法—-ViewHolder。下面我們來看看程式碼。
/*
* 第三種方法(最佳版本)這種版本在第二種版本的基礎上進一步的優化了findViewById這一個過程
* 因為其實每做一次findViewById的時候,都要遍歷整個檢視樹,如果檢視樹比較複雜的話
* 遍歷的時間將會想當的客觀,所以Google專門給了一種資料結構叫ViewHolder
* 同樣是運用了快取的機制,將已經遍歷過的主鍵的ID給存起來
*/
// 獲取納秒時間 更加精確
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.item, null);
holder.image = (ImageView) convertView.findViewById(R.id.iv_image);
holder.title = (TextView) convertView.findViewById(R.id.tv_title);
holder.content = (TextView) convertView
.findViewById(R.id.tv_content);
//將Viewholder與convertView通過setTag繫結起來
convertView.setTag(holder);
}
else {
//getTag()取出關聯的ViewHolder
//通過ViewHolder物件找到對應的控制元件
holder = (ViewHolder) convertView.getTag();
}
ItemBean bean = datalist.get(position);
holder.image.setImageResource(bean.itemImageResId);
holder.title.setText(bean.itemTitle);
holder.content.setText(bean.itemContent);
return convertView;
}
class ViewHolder {
public ImageView image;
public TextView title;
public TextView content;
}
}
最後一種方法不僅利用了ListView的快取機制,更是通過ViewHolder來實現資料檢視的快取,避免了多次通過findViewById來尋找控制元件,在今後的程式思路中也應該借用這種思想。
最後對利用ViewHolder來優化BaseAdapter的思路做一下總結。
(1)建立Bean物件,用於封裝資料
(2)在構造方法中初始化用於對映的資料list
(3)建立ViewHolder類,建立佈局對映關係
(4)判斷convertView,為空則建立,並設定tag,如果不為空則通過tag取出對應的ViewHolder
(5)給ViewHolder中的控制元件設定資料