今天,稍微记录下前几天系统学习的listView的一个优化问题,在这里我们会对几种listView的解决方式来进行比较,从而看出优化后的优点。
首先我们来进行一下前期的准备工作。
public class MainActivity extends Activity {
private ListView mListview;
private List<String> datas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
datas=new ArrayList<String>();
for (int i = 1; i <= 100; i++) {
datas.add(i+"");
}
mListview = (ListView) findViewById(R.id.listView);
mListview.setAdapter(new Myadapter());
}
}
这是MainActivity 中的简单的listView的使用,就不注释了(这里的布局文件就是一个简单ListView)。
一:接着,我们为了侧重讲优化,就直接简单点,将适配器adpater的代码作为内部类放在MainActivity 内部就行,下面就是放在MainActivity 内部的代码:
public class Myadapter extends BaseAdapter {
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 逗逼式:如果单单这样写完全没有对listVie的任何优化处理,没起到一个复用
View view = View.inflate(MainActivity.this, R.layout.my_item, null);
TextView tv (TextView)view.findViewById(R.id.item_tv);
tv.setText(datas.get(position));
return view;
}
}
在这里就是我们常见的一般的写listView的方式(这里的布局文件my_item就是一个简单的TextView),这种方式就像我注释上写的是一样的,是一种逗逼式的方法,因为完全没有起到listview中getView这个方法中的convertView这个参数来起到一个复用的作用。
这里的View.inflate这行代码的刚开始调用的次数是屏幕上第一次显示的数目,比如运行时屏幕上只显示了4个,也就是调用了四次,但当我们向下滑动,出现余下item时会同样调用,并且当我们向上滑动时也同样会重复的调用view.inflate这行代码,这样的缺点会导致当我们不停滑动listview时会发现会越来越卡顿
二:接下来就是采用convertView来进行一般的优化,其实简单点说就是解决上面的view.inflate这行代码重复调用的缺点,在这里,我们主要进行优化的代码放在getView的方法中:
/*
* 当listView的第一条条目Item完全出去在屏幕外时,会放在一个叫recycle的回收站中,
* 所以convertView就是起到一个复用的作用,其实就是上面在recycle回收站中第一条条目的视图,
* 等着后面去复用视图,后面只是更换数据而已 conVertView为null时就是第一次显示在屏幕上的item条数
*
*/
/// 普通式:虽然这里起到一个复用的作用,但是在这里的textView的findViewByID还是没起到复用
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.my_item,null);
}
TextView tv = (TextView) convertView.findViewById(R.id.item_tv);
tv.setText(datas.get(position));
return convertView
在这里,当convertView为空时才会进行view.inflate这行代码,如果不为空,则直接用之前的convertView.findViewById..即可。而当convertView为空的个数是就是第一次显示在屏幕上的item数目,也就是下图中的四个item数。
在接下来的图中就表现出优点:
但是虽然已经比之前的做了优化,但是就像我注释中写的一样,这种方法没有实现TextView的findViewById的复用。
三:所以针对第二种的findViewById没有复用的缺点继续进行优化,我们在这里采用ViewHodler来进行最后的优化:首先我们来写一个内部类的Viewholder:
static class ViewHodle {
TextView textview;
}
在这里注意不管是内部类还是外部类,尽量使用static来修饰,这样做的目的是让其加载一次,并且减少内存占用,加快效率。
接着是getView的方法:
/// 优化式:在这里不仅引用上面的convertView的复用,同样利用Viewhodle来使用其中控件的findViewByID复用
ViewHodle hodler;
///这里的convertView instanceof ViewGroup是对convertView来进行
if (convertView ==null) {
convertView = View.inflate(MainActivity.this, R.layout.my_item, null);
hodler = new ViewHodle();
hodler.textview = (TextView) convertView.findViewById(R.id.item_tv);
convertView.setTag(hodler);
} else {
hodler = (ViewHodle) convertView.getTag();
}
holder.textview.setText(datas.get(position));
return convertView;
这里就是好的优化方式,不仅使用了convertView的复用,并且解决了findViewById的重复调用,其实简单的来说这里就是用了Viewholder来实现一个简单的缓存而已。