今天就来说说ListView这个组件吧,这个组件相信每个App都会涉及到~当然或许很多人已经知道 ListView 的优化。在这里我在详细的说一下listview的优化,顺便让ListView分类显示~~让效果更好~
先来看效果图:
从这个图中可以看出,可以看到数据有100个(0-99),奇数和偶数分类显示,并给每类数据加了一个头~显示是奇数还是偶数的。
步骤:
1.在activity_main布局中编写listview组件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.listview.MainActivity" >
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listview"></ListView>
</RelativeLayout>
2.在MainActivity里为listview设置适配器
private ListView listview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView) findViewById(R.id.listview);
listview.setAdapter(new MyAdapter());
}
3.ListView设置数据,这里就使用模拟数据(0-99),并把数据分成两类(奇数和偶数)
private List<String>jiData;//奇数
private List<String>ouData;//偶数
jiData=new ArrayList<String>();
ouData=new ArrayList<String>();
for(int i=1;i<=100;i++){
if(i%2==0)
ouData.add(i+"");
else
jiData.add(i+"");
}
4.然后要为MyAdapter继承BaseAdapter,实现4个方法~
(1)public int getCount() {} 代表的是返回listView有多少个条目
(2)public Object getItem(int position) {} 指的是返回位置为position的条目
(3)public long getItemId(int position) {} 指的是返回位置为position的条目的Id
(4)public View getView(int position, View convertView, ViewGroup parent) {} 指的是返回每个条目的视图
我们最重要的是第4个方法-getView方法,前面几个这样写:
@Override
public int getCount() {
// TODO Auto-generated method stub
return 1+jiData.size()+1+ouData.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
//俩者效果一样
return null;
//return data.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
现在来看看getView方法,在这个方法里我们要对listview优化和分类显示,所以代码量有点多~
先来分析一下一点都不优化的方式-逗比式:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
/*LayoutInflater layoutInflater=LayoutInflater.from(MainActivity.this);
View view=layoutInflater.inflate(R.layout.listview, null);*/
//不优化,逗比式
System.out.println(convertView);
View view=View.inflate(MainActivity.this, R.layout.listview, null);
TextView tv=(TextView)view.findViewById(R.id.tv);
text=data.get(position);
tv.setText(text);
return view;
}
我们知道getView的调用次数,是有多少个条目就调用多少次吧,那么上面这么写的加载布局和findViewById就会调用100次吧,而每个条目的布局都一样,为什么要重复加载呢,所以要想办法减少加载布局的次数,这样更优化,那该怎么做呢。
我们可以看到getView方法有三个参数,第二个参数convertView还没有使用到,对,有人应该知道就是缓存。
convertView工作原理:
这里屏幕只显示8个条目,你的可能不是,因为每个手机的屏幕大小不一样嘛,不过原理都是一样的。
看到这里我们知道了convertView,所以接下来可以使用convertView来减少加载布局的次数:
那就是所谓的普通式:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
/*LayoutInflater layoutInflater=LayoutInflater.from(MainActivity.this);
View view=layoutInflater.inflate(R.layout.listview, null);*/
//普通式,虽然对视图进行了优化,不用每次都重新加载,但是每次都要findViewById
if(convertView==null){
convertView=View.inflate(MainActivity.this, R.layout.listview, null);
}
TextView tv=(TextView)convertView.findViewById(R.id.tv);
text=data.get(position);
tv.setText(text);
return convertView;
}
这样加载视图就只会调用它第一屏的条目的数量。比如:第一屏显示8个条目,加载视图会调用8次,以后滑动就不会调用了。
到这里看起来是可以了,但是我们可以注意到findViewById也到调用了100次呀,也挺多的,能不能减少呢,答案是肯定的。
那这就是所谓的 高档式:定义一个ViewHolder,将convertView的tag设置为ViewHolder,不为空时重新使用
ViewHolder只是将需要缓存的那些view封装好,convertView的setTag才是将这些缓存起来供下次调用
当你的listview里布局多样化的时候 viewholder的作用就有比较明显的体现了。 当然了,单一模式的布局一样有性能优化的作用 只是不直观。
viewholder就是个静态类 与缓存无关的
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
/*LayoutInflater layoutInflater=LayoutInflater.from(MainActivity.this);
View view=layoutInflater.inflate(R.layout.listview, null);*/
//高档式
ViewHolder holder;
String data ;
if(convertView!=null&&convertView instanceof ViewGroup) {
holder=(ViewHolder) convertView.getTag();
}
else{
convertView=View.inflate(MainActivity.this, R.layout.listview, null);
holder=new ViewHolder();
holder.tv=(TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);//setTag用于携带数据
}
return convertView;
}
//static--只执行一次,而且先执行
static class ViewHolder{
TextView tv;
}
为什么要这样写呢
if (convertView != null && convertView instanceof ViewGroup) {}
因为头的布局和item的布局不一样,不能够全部复用,所以要判断下。
这样就又减少了findViewById的次数了,又再一次优化了。
优化完成了,接下来实现分类显示,首先分析:
数据0-99,分成奇数和偶数,所以各有50个,头的位置分别加在 position = 0 的时候和 position = 51 的时候。
所以:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
/*LayoutInflater layoutInflater=LayoutInflater.from(MainActivity.this);
View view=layoutInflater.inflate(R.layout.listview, null);*/
//高档式
ViewHolder holder;
String data ;
if(position==0){
TextView tv=new TextView(getApplicationContext());
tv.setText("奇数:"+jiData.size());
return tv;
}else if(position<=jiData.size()){
data=jiData.get(position-1);
}else if(position==jiData.size()+1){
TextView tv2=new TextView(getApplicationContext());
tv2.setText("偶数:"+ouData.size());
return tv2;
}else{
data=ouData.get(position-1-jiData.size()-1);
}
return convertView;
}
}
到这里就已经实现了上面的效果。
MainActivity:
public class MainActivity extends Activity {
private ListView listview;
private List<String>data;
private List<String>jiData;//奇数
private List<String>ouData;//偶数
private String text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView) findViewById(R.id.listview);
jiData=new ArrayList<String>();
ouData=new ArrayList<String>();
for(int i=1;i<=100;i++){
if(i%2==0)
ouData.add(i+"");
else
jiData.add(i+"");
}
listview.setAdapter(new MyAdapter());
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return 1+jiData.size()+1+ouData.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
//俩者效果一样
return null;
//return data.get(position);
}
@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
/*LayoutInflater layoutInflater=LayoutInflater.from(MainActivity.this);
View view=layoutInflater.inflate(R.layout.listview, null);*/
//高档式
ViewHolder holder;
String data ;
if(position==0){
TextView tv=new TextView(getApplicationContext());
tv.setText("奇数:"+jiData.size());
return tv;
}else if(position<=jiData.size()){
data=jiData.get(position-1);
}else if(position==jiData.size()+1){
TextView tv2=new TextView(getApplicationContext());
tv2.setText("偶数:"+ouData.size());
return tv2;
}else{
data=ouData.get(position-1-jiData.size()-1);
}
/*if(position<jiData.size())
data=jiData.get(position);
else
data=ouData.get(position-jiData.size());*/
if(convertView!=null&&convertView instanceof ViewGroup) {
holder=(ViewHolder) convertView.getTag();
}
else{
convertView=View.inflate(MainActivity.this, R.layout.listview, null);
holder=new ViewHolder();
holder.tv=(TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);//setTag用于携带数据
}
//text=data.get(position);
//分偶数和奇数
holder.tv.setText(data);
return convertView;
}
}
//static--只执行一次,而且先执行
static class ViewHolder{
TextView tv;
}
}
源码:
下载