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传值就不是每一个实例都做了