Android开发专栏之ListView一两种适配器的使用和优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012320459/article/details/47667869

前言:

最近花了几天时间研究了下ListView的优化,然后写了一些demo,现在把这些天的东西总结。ListView的适配器主要有三种,ArrayAdapter,SimpleAdapter,SimpleCursorAdapter,我对于简单游标适配器还不了解,这里只说前两种。优化方式这里提到的主要就是converView,ViewHolder.还有加载图片的优化,这里先不涉及,我到后面会补充哦。
不同的适配器的区别主要是使用的数据结构不同,数组适配器就是使用数组,而简单适配器一般使用HashMap或者Map。

两种适配器:

1.ArrayAdapter:

数组适配器有三种使用方法
第一种: 是直接使用一个TextView作为根布局

<?xml version="1.0" encoding="utf-8"?>

<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_itemContent_arrayAdapter1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

然后直接调用API里的ArrayAdapter就可以了:

//用这种方式来创建listView
        ListView mlistView=new ListView(this);
        String[] items={"1.ArrayAdapterData1",
                "2.ArrayAdapterData2",
                "3.ArrayAdapterData3",
                "4.ArrayAdapterData4"};
        //创建数组适配器方式1
        //参数1:context
        //参数2:listView的layout的id,要注意的是这个layout里面只能有一个控件就是TextView,连layout都不可以有!否则程序崩溃
        //数组
 ArrayAdapter<String> arrayAdapter=new  ArrayAdapter<String>(this,R.layout.listview_arrayadapter_layout1,items);

Demo运行:

这里写图片描述

第二种:可以有Layout作为ListView的根布局,并且可以有几个控件,但是只能填充其中一个TextView的内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<TextView
    android:id="@+id/tv_itemContent_arrayAdapter2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
<Button
    android:id="@+id/bt_itemButton_arrayAdapter2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="button"
    android:onClick="onButtonClick"
    />
</LinearLayout>

然后这样调用:

 //用这种方式来创建listView
        ListView mlistView=new ListView(this);
        String[] items={"1.ArrayAdapterData1",
                "2.ArrayAdapterData2",
                "3.ArrayAdapterData3",
                "4.ArrayAdapterData4"};
  //创建数组适配器方式2
        //参数1:context
        //参数2:listView的layout的id,里面有多个控件
        //要填充数组数据的textView的id
        //数组
  ArrayAdapter<String>  arrayAdapter=
                                new  ArrayAdapter<String>(this,R.layout.listview_arrayadapter_layout2,R.id.tv_itemContent_arrayAdapter2,items);

demo运行:
这里写图片描述

第三种:可以自定义ArrayAdapter,因为数组适配器的内容只能是一个元素,无法填充每行有多个控件的ListView,所以只要把数组元素换成自定义的类对象就可以了,然后还要重写ArrayAdapter,因为原本的ArrayAdapter的getView()方法无法根据我们自定义的类对象来填充数据。
自定义类:

/**自定义数组适配器的item类
 * Created by daniel on 15-8-14.
 */
public class Fruit {
    private int imageId;
    private String name;
    public Fruit(int imageId,String name){
        this.imageId=imageId;
        this.name=name;
    }
    public int getImageId(){
        return imageId;
    }
    public void setImageId(int imageId){
        this.imageId=imageId;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }
    @Override
    public String toString(){
        return "Fruit{"+
                "imageId="+this.imageId+
                ",name='"+this.name+'\''+
                '}';
    }
}

自定义的适配器类:

/**自定义的ArrayAdapter
 * Created by daniel on 15-8-14.
 */
public class FruitAdapter extends ArrayAdapter<Fruit>{
    private List<Fruit> list;
    private Context context;
    private int resourceId;
    private LayoutInflater inflater;
    /**
     * 构造方法
     * @param context
     * @param resourceId ListView的layout的id
     * @param list 填充数据
     */
    public FruitAdapter(Context context,int resourceId,List<Fruit> list){
        super(context,resourceId,list);
        inflater=LayoutInflater.from(context);
        this.context=context;
        this.resourceId=resourceId;
        this.list=list;
    }
    @Override
    public View getView(int position,View convertView,ViewGroup parent){
        ViewHolder viewHolder=null;
        Fruit fruit=getItem(position);
        if(convertView==null){
            convertView=inflater.inflate(R.layout.listview_arrayadapter_layout3,parent,false);
            viewHolder=new ViewHolder();
           viewHolder.mitemImage=(ImageView)convertView.findViewById(R.id.iv_itemImage_arrayAdapter3);
            viewHolder.mitemName=(TextView)convertView.findViewById(R.id.tv_itemContent_arrayAdapter3);
            convertView.setTag(viewHolder);
        }else{
            viewHolder=(ViewHolder)convertView.getTag();
        }
        viewHolder.mitemImage.setImageResource(fruit.getImageId());
        viewHolder.mitemName.setText(fruit.getName());
        return convertView;
    }
    private final static class ViewHolder{
        ImageView mitemImage;
        TextView mitemName;
    }
}

这么调用:

 private List<Fruit> mfruitList;
    private ListView mlistView;
    FruitAdapter fruitAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_view__array_adapter__demo2);
        mlistView=(ListView)findViewById(R.id.listView_arrayAdapter3);
        mfruitList=new ArrayList<Fruit>();
        initData();
        fruitAdapter=new FruitAdapter(this,R.layout.listview_arrayadapter_layout3,mfruitList);
        mlistView.setAdapter(fruitAdapter);
        mlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Fruit fruit=mfruitList.get(position);
                Toast.makeText(ListView_Extends_ArrayAdapter_Demo.this, fruit.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * 填充数据到数组里
     */
    private void initData() {
        Fruit apple=new Fruit(R.drawable.ic_launcher,"苹果");
        mfruitList.add(apple);
        Fruit waterMelon=new Fruit(R.drawable.ic_launcher,"西瓜");
        mfruitList.add(waterMelon);
    }

demo运行:
这里写图片描述

2.SimpleAdapter:

SimpleAdapter一般使用的是HashMap,根据不同的key向不同的控件内填充内容。

<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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.study.daniel.gridviewtest.ListView_SimpleAdapter_Demo">
<ImageView
    android:id="@+id/iv_itemImage_simpleAdapter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="3dp"
    android:src="@drawable/ic_launcher"
    />
<TextView
    android:id="@+id/tv_itemName_simpleAdapter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@+id/iv_itemImage_simpleAdapter"
    android:layout_marginTop="5dp"
    android:text="itemName"
    />
<TextView
    android:id="@+id/tv_itemPhone_simpleAdapter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/tv_itemName_simpleAdapter"
    android:layout_toRightOf="@+id/iv_itemImage_simpleAdapter"
    android:layout_alignBaseline="@+id/iv_itemImage_simpleAdapter"
    android:text="itemPhone"
    />
<TextView
    android:id="@+id/tv_itemRegion_simpleAdapter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@+id/tv_itemPhone_simpleAdapter"
    android:layout_alignBaseline="@+id/tv_itemPhone_simpleAdapter"
    android:layout_marginLeft="10dip"
    android:text="itemRegion"
    />
</RelativeLayout>

调用:

 private String[] itemNames={"Mr 1","Mr 2","Mr 3","Mr 4" ,"Miss 5"};
    private String[] itemPhones={"000","001","002","003","004"};
    private String[] itemRegions={"纽约","东京","哥伦比亚","安徽","未知"};
    private ArrayList<Map<String,Object>> mInfos=new ArrayList<Map<String,Object>>();
    private ListView mlistView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.listview_simpleadapter_layout);
        //数据填充
        for(int i=0;i<itemNames.length;i++){
            Map<String,Object> item=new HashMap<String,Object>();
            item.put("itemName",itemNames[i]);
            item.put("itemPhone",itemPhones[i]);
            item.put("itemRegion",itemRegions[i]);
            item.put("itemImage",R.drawable.ic_launcher);
            mInfos.add(item);
        }
        mlistView=new ListView(this);
        SimpleAdapter simpleAdapter=new SimpleAdapter(this,mInfos,R.layout.listview_simpleadapter_layout,
                new String[]{"itemName","itemPhone","itemRegion","itemImage"},
                new int[]{R.id.tv_itemName_simpleAdapter,R.id.tv_itemPhone_simpleAdapter,R.id.tv_itemRegion_simpleAdapter,R.id.iv_itemImage_simpleAdapter}
        );
        mlistView.setAdapter(simpleAdapter);
        setContentView(mlistView);}

demo运行如下:
这里写图片描述

优化:

关于优化主要就是两步,(这个理解起来要花一些时间,我研究了三天才搞懂)一个是防止每次都将ListView的每一行的布局文件实例化,所以在向上翻动的时候重用第一页的布局对象,及getView的convertView参数。但是这只是重用了布局文件,防止了布局文件实例化的IO操作,ListView每一行可能有很多控件,比如Button,TextView,ImageView等,这些控件从xml文件里面读取并且实例化成对象也是非常耗费内存的,所以也得重用,可以使用ViewHolder,这个类的对象中将保存listView每一行的控件为成员变量,然后用setTag和这个convertView绑定在一起,其实看下源码就是保存这个Object对象在convertView里面了,方便下次取出。然后每次getView的时候只要给ViewHolder的里面的成员变量设置显示内容就可以了。因为这些子布局的控件已经变成viewHolder对象的成员变量了,设定它们的内容就是设定控件的内容。
另外,如果ListView不同的行具有不同的子布局的话,就需要不同的ViewHolder了,有几种布局就需要几种viewHolder,因为保存的控件不同了,然后重写两个函数getViewTypeCount,getViewType,在getView里面显式调用getViewType方法,在选择不同的viewHolder时候加一个switch判断就好了。代码这里就不展示,代码会上传,大家自行下载。
demo运行
只有一种布局的优化demo:
这里写图片描述
多种布局的优化demo:
这里写图片描述

非常容易犯错的问题:

在写多种布局的优化demo时候,程序总是崩溃,调bug都调不出来,后来找了整整一天,才发现是因为布局种类的type下标必须从0开始!!如果从1开始,就会造成程序崩溃!

代码上传:

1.ArrayAdapter使用方式1,2的demo:
http://download.csdn.net/detail/u012320459/9007389
2.ArrayAdapter使用方式3(自定义)的demo:
http://download.csdn.net/detail/u012320459/9007423
3.SimpleAdapter使用demo:
http://download.csdn.net/detail/u012320459/9007463
4.扩展自BaseAdapter的适配器的单一布局的优化demo:
http://download.csdn.net/detail/u012320459/9007469
5.扩展自BaseAdapter的适配器的多种布局的优化demo:
http://download.csdn.net/detail/u012320459/9007655

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页