android的ListView的适配器的使用

来源:互联网 发布:linux查看机器配置 编辑:程序博客网 时间:2024/04/28 17:46

        android的控件ListView是AdapterView的子类,凡是AdapterView的子类,都有一个方法,setAdapter(),所以ListView也不例外,这里ListView的适配器常用的有四个,分别是ArrayAdapter,SimpleAdapter,SimpleCursorAdapter,BaseAdapter。在继承关系上,父类是Adapter,然后在ListView使用的Adapter的共同父类是ListAdapter接口,而我们常用的四个适配器是ListAdapter的子类。

        这里可以使用LIstView在具体实现时的每一项是怎么样的对适配器进行区分。其实适配器的关键就在于对ListView的每一项的操作而已。

        这里使用最简单的就是ArrayAdapter,SimpleAdatper两个,但是他们的使用限制也是很明显的,基本上使用的都是字符串,整型,这里使用图片的话基本都是使用id获取的。而子项的布局也是id获取的。应该说在使用适配器上,基本上布局,资源都是使用ID获取的,特别是ArrayAdapter,SimpleAdapter,SimpleCursorAdapter更是如此。

        对于ArrayAdapter的代码一般实例化ArrayAdapter adapter=new ArrayAdapter(contexty,itemlayout,itemarray),也就是说ArrayAdapter的第二个参数就是每一个项的布局,每个项的布局对应第三个参数的每一个元素。也就是说,第三个参数的每一个元素使用第二个参数为布局。可以使用如下代码实现

ListView view=new ListView(this);
String[] str={"hn","hange","hangeqq","hangeqqcaomm"};
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,R.layout.han,str);
view.setAdapter(adapter);
re.addView(view);


        布局R.layout.han的代码如下

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />


        这里需要注意对于XML作为android的布局,其实说白了就是使用XML实现一个View,所以在一个layout布局里面布局并非必要,因为布局本身就是View,但是需要注意,在定义的XML文件中,xmlns:android="http://schemas.android.com/apk/res/android"却是必须的。说白了就是XML定义的View需要加上一些让android能够是别的标签和一些其他的属性。

        上面的ArrayAdapter实现的ListView是一个每一项都是字符串的ListView。

        对于SimpleAdapter在使用上比ArrayAdapter复杂点,他实现的每一项不是仅仅就是一个元素,他实现的ListView的每一项可以加入多个元素元素。SimpleAdapter adapter=new SimpleAdapter(Context,data,itemlayout,datakey,dataitemlayout)这里需要注意,第二个参数是我们使用的数据,他一般是一个LIst<Map<String,Object>>列表,这个列表每一项即使ListView的每一项,而第三个参数就是ListView的每一项的布局,第四个项则是列表里面的每一个Map元素的键,最后一个参数则是列表里面的每一个Map元素的值的布局,这个布局实际上就在第二个参数布局里面,下面是代码

ListView view=new ListView(this);
ArrayList<Map<String,Object>> list=new ArrayList<Map<String,Object>>();

Map<String,Object> map1=new HashMap<String,Object>();
Map<String,Object> map2=new HashMap<String,Object>();
Map<String,Object> map3=new HashMap<String,Object>();
map1.put("button", "bm1");
map1.put("text", "bm1button");
map1.put("image", R.drawable.d);
map2.put("button", "bm2");
map2.put("text", "bm2button");
map2.put("image", R.drawable.m);
map3.put("button", "bm3");
map3.put("text", "bm3button");
map3.put("image", R.drawable.y);
list.add(map1);
list.add(map2);
list.add(map3);
SimpleAdapter adapter=new SimpleAdapter(this,list,R.layout.hange,
new String[]{"button","text","image"},
new int[]{R.id.button1,R.id.textView1,R.id.imageView1});
view.setAdapter(adapter);
re.addView(view);


而R.layout.hange布局代码如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="Button" />


    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/button1"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/button1"
        android:text="TextView" />


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/textView1"/>


</RelativeLayout>


这里注意,SimpleAdapter的限制是十分明显的,这里使用的图片是使用id获取的,而不是通过代码获取的。

        其实ArrayAdapter,SimpleAdapter两个的关键都在于实例化而已,关键就在于每一个项的布局。


        其实对于ArrayAdapter,SimpleAdapter的使用是十分有限的,虽然简单,但同样的使用也是非常不方便的,所以绝大多数情况下,我们使用抽象类BaseAdapter实例化一个我们自己需要的适配器。

        对于BaseAdapter抽象类,我们在继承它之后需要实现的方法有:getCount(),getItem(int),getItemId(int),getView(int,View,View)等,其中getCount()返回的是数据源的项数,这决定了后面getView()方法运行的次数。getItem()返回的是数据源的每一项。getItemId()返回的是数据源的每一项的ID。而这些都不是最重要的,最重要的是getView(int position,View convertView,ViewGroup parent)这个方法中第一个参数是数据源的项的位置,第二个项就是ListView的每一个项,最后一个参数其实就是ListView,而这些都是可以从参数的命名中看出来的,而这个方法返回的View其实是ListView的项,相当于第二个参数。当然了,第二个参数是系统传给我们使用的,我们不需要的话可以在getView()里面在创建一个View然后返回给ListView。下面是一个简单的BaseAdapter实例

this.context=this;
this.list=new ArrayList<Bitmap>();
try {
Bitmap bm1=BitmapFactory.decodeStream(getAssets().open("d.png"));
Bitmap bm2=BitmapFactory.decodeStream(getAssets().open("m.png"));
Bitmap bm3=BitmapFactory.decodeStream(getAssets().open("y.png"));
list.add(bm1);
list.add(bm2);
list.add(bm3);
} catch (IOException e) {
e.printStackTrace();
}
ListView view=new ListView(this);
view.setAdapter(new BaseAdapter(){
@Override
public int getCount() {

return list.size();
}
@Override
public Object getItem(int position) {

return list.get(position);
}
@Override
public long getItemId(int position) {

return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView image=new ImageView(context);
image.setImageBitmap(list.get(position));
return image;
}

});
re.addView(view);


这里实现的BaseAdapter将每一个图片作为ListView的每一项。

        其实BaseAdapter里面,getView()方法是最关键的方法,因为他返回的View决定了ListView的每一项是怎么样的。

        适配器在使用XML文件为ListView的每一项加载布局的时候,XML文件里面最外层的布局类只是起到一个控制里面的控件的摆放的作用而已,而布局类的大小并没有起到作用。所以可以在一个最外层是布局类的XML文件里面摆放自己想要的ListView的每一项的控件摆放样式。

        这里注意除了BaseAdapter可以在自定义中为ListView的每一项添加监听从而每一项都可以获得焦点之外,其他的系统提供的适配器在被ListView使用中ListView的每一项基本都是不能获得焦点的,因为点击操作都被ListView的item所获取了。这里涉及到一个非常关键的知识点,那就是AdapterView其实本身已经定义了监听,这些AdapterView定义的监听都是用于监听AdapterView的每一项用的,这里AdapterView定义了OnItemClickListener,OnItemLongClickListener,OnItemSelectedListener三种监听。

        最后讲一下SimpleCursorAdapter。CursorAdapter的子类是ResourceCursorAdapter,ResourceCursorAdapter的子类是SimpleCursorAdapter。该类在使用上基本上和前面的适配器的使用基本一样,关键看构造函数就知道了new SimpleCursorAdapter(Context,int layout,Cursor cursor,String[ ] from,int[ ] to),但是 注意这里有一个Cursor,所以很容易猜到这个类可以操作数据库,因为数据库可以产生Cursor,也就是说相比前面的适配器,SimpleCursorAdapter只是将数据源换成了数据库的Cursor进行操作。


        当然,其实对于LIstView还有一个最关键的点,那就是优化,对于ListView来说,他需要频繁的加载很多资源,所以对于所加载的东西的如何最优化的加载,对于没在屏幕现实的东西,如何优化的暂时删除这都是ListView应该考虑的东西。

        ListView的优化。其实LIstView的优化基本上使用的都是BaseAdapter进行的。这里在使用BaseAdapter的getView方法的时候返回的View如果是自定义的View那么其实这样是不利于优化的,应该尽量使用getView()方法参数里面的View作为返回View,因为这个View相当于一个缓存,当ListView的项不可见时,缓存数据,当数据需要加载时就只需要更新ListView项的界面就可以了。使用getView()里面提供的View进行绘制可以避免绘制次数太多造成的效率变慢问题,因为在android中绘制UI界面是最耗时的。其实ListView的项View的数量仅仅维持在屏幕所能显示的最多项的数目而已,我们在使用getView()提供的参数View作为项View时,其实getView()提供给我们的View很大程度上都是重复的。总的来说,getView()提供的参数View具有缓存功能,同时多次使用getView()时,参数View基本上可能是同一个View对象的,我们就是在给同一个View对象设置不同UI而已。

        在ListView中可以使用setTag(),getTag()的方法定位控件,然后使用findViewByTag()就可以找到控件了,这比使用findViewById()使用id层层查找要快很多。

        其实在使用ListView时,最重要的优化就在于缓存,也就是但数据变得很大的时候对于数据的处理方式应该在缓存上着手。可以给ListView设置两级缓存,一级缓存使用LinkedHashMap<String,Bitmap>,二级缓存使用ConcurrentHashMap<String,SoftReference<Bitmap>>,一级缓存保留Bitmap的强引用,并且设置容量大小,这样当内存不足时,可以将不常使用的元素放入二级缓存,二级缓存保存的是Bitmap的软引用,所以当内存吃紧的时候可以让GC回收。如果ListView在使用时不用缓存,每次需要加载图片时都要去网络下载,那么这样是耗时耗流量而且很慢的。使用缓存不仅可以节省流量,加快加载速度,而且速度快省流量。应该说这里的缓存涉及到对象的引用。

        总的来说,LIstView的优化其实就是在缓存的使用上,如何设置缓存是ListView优化的关键。






0 0
原创粉丝点击