1. BaseAdapter適配器重寫 之getView():
(1)View getview(int position, View convertview, ViewGroup parent )
第一個參數position----------該視圖在適配器數據中的位置
第二個參數convertView-----舊視圖
第三個參數parent------------此視圖最終會被附加到的父級視圖
特別注意:convertview參數
首先講下ListView的原理:ListView中的每一個Item顯示都需要Adapter調用一次getView的方法,這個方法會傳入一個convertView的參數,返回的View就是這個Item顯示的View。
如果當Item的數量足夠大,再為每一個Item都創建一個View對象,必將占用很多內存,創建View對象(mInflater.inflate(R.layout.lv_item, null);從xml中生成View,這是屬於IO操作)也是耗時操作,所以必將影響性能。
Android提供了一個叫做Recycler(反復循環器)的構件,就是當ListView的Item從上方滾出屏幕視角之外,對應Item的View會被緩存到Recycler中,相應的會從下方生成一個Item,而此時調用的getView中的convertView參數就是滾出屏幕的Item的View,所以說convertView 我們可以復用它,這樣就省去了new View的大量開銷。
(2)ViewHolder(自定義的):
getView方法:
public View getView(int position, View convertView, ViewGroup parent) { System.out.println("getView " + position + " " + convertView); ViewHolder holder = null; if (convertView == null) { convertView = mInflater.inflate(R.layout.lv_item, null); holder = new ViewHolder(); holder.textView = (TextView)convertView.findViewById(R.id.tv_text); convertView.setTag(holder); } else { holder = (ViewHolder)convertView.getTag(); } holder.textView.setText(mData.get(position)); return convertView; }
ViewHolder:
package com.shinylife.smalltools; import android.widget.ImageView; import android.widget.TextView; public class ViewHolder { public ImageView imgView; public TextView textView; }
為什么要ViewHolder(自定義的)這樣一個東西, 因為無論convertView是不是null, 都需要對ViewHolder中的TextView和ImageView進行賦值操作, 貌似沒有什么必要.
其實不是這么簡單, 這樣做是一種拿空間換時間的方式. 增加一個對象ViewHolder , 卻省去了一系列的findViewById()的時間,大家都知道, 在一個View的樹形結構上使用findViewById()查找控件是需要時間的, 而且這個樹形結構越復雜, 花費的時間越多。
注意:
我們都知道在getView方法中的操作是這樣的:先從xml中創建view對象(inflate操作,我們采用了重用convertView方法優化),然后在這個view去findViewById,找到每一個子View,如:一個TextView等。
這里的findViewById操作是一個樹查找過程,也是一個耗時的操作,所以這里也需要優化,就是使用viewHolder,把每一個子View都放在Holder中,當第一次創建convertView對象時,把這些子view找出來。
然后用convertView的setTag將viewHolder設置到Tag中,以便系統第二次繪制ListView時從Tag中取出。當第二次重用convertView時,只需從convertView中getTag取出來就可以。
(3)setTag()/getTag():View中的setTag(Onbect)表示給View添加一個格外的數據,以后可以用getTag()將這個數據取出來。
可以用在多個Button添加一個監聽器,每個Button都設置不同的setTag。這個監聽器就通過getTag來分辨是哪個Button 被按下:
1 import android.app.Activity; 2 3 import android.os.Bundle; 4 5 import android.view.View; 6 7 import android.widget.Button; 8 9 public class Main extends Activity { 10 11 @Override 12 13 public void onCreate(Bundle savedInstanceState) { 14 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.main); 17 18 Button button1 = (Button) findViewById(R.id.Button01); 19 Button button2 = (Button) findViewById(R.id.Button02); 20 Button button3 = (Button) findViewById(R.id.Button03); 21 Button button4 = (Button) findViewById(R.id.Button04); 22 23 MyListener listener = new MyListener(); 24 button1.setTag(1); 25 button1.setOnClickListener(listener); 26 27 button2.setTag(2); 28 button2.setOnClickListener(listener); 29 30 button3.setTag(3); 31 button3.setOnClickListener(listener); 32 33 button4.setTag(4); 34 button4.setOnClickListener(listener); 35 36 } 37 38 public class MyListener implements View.OnClickListener { 39 40 @Override 41 public void onClick(View v) { 42 int tag = (Integer) v.getTag(); 43 44 switch (tag) { 45 case 1: 46 System.out.println("button1 click"); 47 break; 48 49 case 2: 50 System.out.println("button2 click"); 51 break; 52 53 case 3: 54 System.out.println("button3 click"); 55 break; 56 57 case 4: 58 System.out.println("button4 click"); 59 break; 60 } 61 } 62 } 63 64 } 65
在寫ListView 時候要重寫BaseAdapter:
需要在沒個item都加上button 點擊button做相應操作
這個時候需要button里面設置下 這行的屬性
button.setTag(item.user.name);
然后處理button事件。
這個東西在一些需要用到Adapter自定控件顯示方式的時候非常有用
Adapter 有個getView方法,可以使用setTag把查找的view緩存起來方便多次重用:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mWidgetsSwitchApp.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.app_gallery_item, null);
vh = new ViewHolder();
vh.view1 = (ImageView) convertView.findViewById(R.id.view1);
vh.view2 = (ImageView) convertView.findViewById(R.id.view2);
vh.view3 = (ImageView) convertView.findViewById(R.id.view3);
vh.view4 = (ImageView) convertView.findViewById(R.id.view4);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
//其他的代碼可以直接使用 vh.view1、vh.view2、vh.view3 、vh.view4
}
你可以看看android的源碼,特別有listview的,你就會發現這個函數很多時候有妙用!呵呵!
我的一點理解是,綁定數據,特別是綁定數據到view。而且可以用getTag()取得,很方便,而且是任意類型的數據,真的很酷。
在實例BaseAdapter()的getView(position, convertView, par)里有用到。convertView這里會用到setTag() getTag()。就可以生成convertView並復用里面的widget,一直覺得這個東西沒啥用setTag(),不過只要能用上 就是比較巧的了
在一個程序中呢 我有好多個button 我想點擊一個出現1, 點擊第二個出現2
for (int i = 0; i < 20; i++) {
cells[i] = (ImageView) findViewById(cellIDs[i]);
cells[cellnumber++].setOnClickListener(new OnClickListener() {
public void onClick(View v){
cellClicked(cellnumber, v);
}});
}
上面的代碼效率不高 而且 無論點擊哪一個都會出現21 當然這是我邏輯錯誤
那怎么實現呢
OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
int cellId = (Integer) v.getTag();
cellClicked(cellId, v);
}
}
View v;
for (int i = 0; i < 20; i++) {
v = findViewById(cellIDs[i]);
v.setOnClickListener(listener);
v.setTag(i);
}
這樣呢就實例話一個listener,同時通過tag傳值就不是每一個實例都做了