最近在项目中需要对listview中的数据进行分组,我构思的基本原理就是,在适配器Adapter的getView()方法中,根据当前item类型,分别加载不同的布局,这样是很容易实现的,想必大家都很清楚这个小东西。但是问题是,这样的代码写下来listview在数据很多时,上下滑动会很卡,于是乎就想到了用viewHolder来进行缓存, 难度就在对不同的item进行不同的缓存。
下面是我实现的效果:
第1、 2,3 、 4,5,6 、7、 8,9、 10,11,12......如此循环下去,下面是我实现的代码:
public class listViewTest extends Activity { /** Called when the activity is first created. */ ListView listView; MyAdapter listAdapter; ArrayList<String> listString; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); listView = (ListView)this.findViewById(R.id.listview); listString = new ArrayList<String>(); for(int i = 0 ; i < 100 ; i++) { listString.add(Integer.toString(i)); } listAdapter = new MyAdapter(this); listView.setAdapter(listAdapter); } class MyAdapter extends BaseAdapter{ Context mContext; LinearLayout linearLayout = null; LayoutInflater inflater; TextView tex; final int VIEW_TYPE = 3; final int TYPE_1 = 0; final int TYPE_2 = 1; final int TYPE_3 = 2; public MyAdapter(Context context) { // TODO Auto-generated constructor stub mContext = context; inflater = LayoutInflater.from(mContext); } @Override public int getCount() { // TODO Auto-generated method stub return listString.size(); } //每个convert view都会调用此方法,获得当前所需要的view样式 @Override public int getItemViewType(int position) { // TODO Auto-generated method stub int p = position%6; if(p == 0) return TYPE_1; else if(p < 3) return TYPE_2; else if(p < 6) return TYPE_3; else return TYPE_1; } @Override public int getViewTypeCount() { // TODO Auto-generated method stub return 3; } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return listString.get(arg0); } @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 viewHolder1 holder1 = null; viewHolder2 holder2 = null; viewHolder3 holder3 = null; int type = getItemViewType(position); //无convertView,需要new出各个控件 if(convertView == null) { Log.e("convertView = ", " NULL"); //按当前所需的样式,确定new的布局 switch(type) { case TYPE_1: convertView = inflater.inflate(R.layout.listitem1, parent, false); holder1 = new viewHolder1(); holder1.textView = (TextView)convertView.findViewById(R.id.textview1); holder1.checkBox = (CheckBox)convertView.findViewById(R.id.checkbox); Log.e("convertView = ", "NULL TYPE_1"); convertView.setTag(holder1); break; case TYPE_2: convertView = inflater.inflate(R.layout.listitem2, parent, false); holder2 = new viewHolder2(); holder2.textView = (TextView)convertView.findViewById(R.id.textview2); Log.e("convertView = ", "NULL TYPE_2"); convertView.setTag(holder2); break; case TYPE_3: convertView = inflater.inflate(R.layout.listitem3, parent, false); holder3 = new viewHolder3(); holder3.textView = (TextView)convertView.findViewById(R.id.textview3); holder3.imageView = (ImageView)convertView.findViewById(R.id.imageview); Log.e("convertView = ", "NULL TYPE_3"); convertView.setTag(holder3); break; } } else { //有convertView,按样式,取得不用的布局 switch(type) { case TYPE_1: holder1 = (viewHolder1) convertView.getTag(); Log.e("convertView !!!!!!= ", "NULL TYPE_1"); break; case TYPE_2: holder2 = (viewHolder2) convertView.getTag(); Log.e("convertView !!!!!!= ", "NULL TYPE_2"); break; case TYPE_3: holder3 = (viewHolder3) convertView.getTag(); Log.e("convertView !!!!!!= ", "NULL TYPE_3"); break; } } //设置资源 switch(type) { case TYPE_1: holder1.textView.setText(Integer.toString(position)); holder1.checkBox.setChecked(true); break; case TYPE_2: holder2.textView.setText(Integer.toString(position)); break; case TYPE_3: holder3.textView.setText(Integer.toString(position)); holder3.imageView.setBackgroundResource(R.drawable.icon); break; } return convertView; } } //各个布局的控件资源 class viewHolder1{ CheckBox checkBox; TextView textView; } class viewHolder2{ TextView textView; } class viewHolder3{ ImageView imageView; TextView textView; } }
getViewTypeCoun在看了AbsListView.java的源代码发现,在ObtainView()方法中,它会来判断当前litview中的type个数,也就是我复写getViewTypeCount()的原因,我们这里有三个不同的item布局,他们都被缓存了起来,所以在getview()方法中,当上下滑动时,就没有必要再重新做inflate和findViewById()的工作,直接使用回收来的viewHolder对象,大大的提高了listview滑动的流畅性。