深入理解Adapter
一、ListView
ListView是Android开发过程中较为常见的组件之一,它将数据以列表的形式展现出来。一般而言,一个ListView由以下三个元素组成:
1.View:展示列表视图,通常是一个xml所指定的。大家都知道Android的界面基本上是由xml文件负责完成的,所以ListView的界面也理所应当的使用了xml定义。例如在ListView中经常用到的“android.R.layout.simple_list_item_1”等,
就是Android系统内部定义好的一个xml文件。
2.Adapter适配器:用于将不同的数据映射到View上。不同的数据对应不同的适配器,如ArrayAdapter,CursorAdapter,
SimpleAdapter等, 他们能够将数组,指针指向的数据,Map等数据或基本组件映射到View上。也正是由于适配器的存在,使得ListView的使用相当灵活,经过适配器的处理后,在 view看来所有的数据映射过来都是一样的。
3.数据:具体的数据和资源。可以是字符串图片、Map映射等,通过适配器这些数据将会被现实到 ListView上。
总之,所有的数据和资源要显示到ListView上都通过适配器来完成。ArrayAdapter,CursorAdapter,
SimpleAdapter为系统已有的适配器,可以将如数组、Cursor指向的数据(一般为数据库)、Map里的数据。
二、深入理解Adapter
1.概要:Adapter是连接后端数据和前端视图显示的适配器接口,是数据和UI(View)之间的桥梁。通过适配器,可以将不同的数据映射并显示到View上。在常见的View(ListView、GridView)等地方都需要用到Adapter。对于Data、Adapter、View的关系,如下图所示:
2.Android中Adapter类
(1)BaseAdapter适配器:为一个抽象类,使用该类可以实现更为复杂的ListView。通过文档可以看出,ArrayAdapter,CursorAdapter,
SimpleAdapter都继承于BaseAdapter。所以通过继承BaseAdapter就可以完成自己的Adapter,可以将任何复杂组合的数据和资源,以任何你想要的显示效果展示处理。继承BaseAdapter之后,需要重写以下四个方法:getCount,getItem,getItemId,getView。但是,ArrayAdapter,CursorAdapter, SimpleAdapter则无须要全部重写上述四种方法。
(2)ArrayAdapter适配器:支持泛型操作,最为简单,只能展示一行字符串。
(3)SimpleAdapter适配器:有最好的扩充性,可以自定义出各种效果(字符串、图片、Map集),通常使用xml布局文件来指定视图。
(4)SimpleCursorAdapter适配器:可以适用于简单的纯文字型ListView,它需要Cursor的字段和UI的id对应起来。如需要实现更复杂的UI也可以重写其他方法。可以认为是SimpleAdapter对数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。
3.ListView加载adapter一般过程
(1)先判断adapter有多少数据项,根据这个数据确定有多少item(列表项). -----getCount()方法实现
(2)确定每个item里加载哪个View. -----getView()方法实现
(3)向对应的View中加载需要显示的数据
4.ArrayAdapter实例分析
(1)开发基本思路
ArrayAdapter适配器支持泛型操作,列表的每一项只能显示一串字符,不能显示图片等资源数据。
*使用字符串数组作为数据源
a.实现一个字符串数组作为数据源(List集)(数组元素有几个,就有几个列表项)
b.实例化一个ArrayAdapter<String> 适配器对象,用于装配数据源到指定的View.
ArrayAdapter<String> adapter=new ArrayAdapter<String>( this,android.R.layout.simple_expandable_list_item_1, strs);
c.将ArrayAdapter适用于ListActivity的ListView
setListAdapter(adapter);
*使用List集合(ArrayList)作为数据源
a.实例化一个ListView对象
b.实例化一个ArrayAdapter<String>对象(集合中数据项类型为String),将Map集合中的数据项映射到列表项中;
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData());
c.装配Adapter到ListView中并显示ListView视图
listview.setAdapter(adapter); //装配Adapter到ListView
setContentView(listview); //将list视图显示
(2)源代码分析一
MainActivt.java
package com.example.android_arraylist_1;
mport android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
public class MainActivity extends ListActivity
{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String[] strs={"第一项","第二项","第三项","第四项"}; //列表项数据
ArrayAdapter<String> adapter=new ArrayAdapter<String>( //实例化一个ArrayAdapter适配器来装配数据
this, //上下文
android.R.layout.simple_expandable_list_item_1, //列表的每一行布局,只显示一行文字
strs); //数据源(一个List集合)
setListAdapter(adapter); //将List集合数据显示在List视图中
}
}
分析:
上面代码使用了ArrayAdapter(Context context, int textViewResourceId, List<T> objects)来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用setAdapter()完成适配的最后工作。
效果:
(3)源码分析二
ArrayListActivity.java
package com.example.android_arraylist_2;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class ArrayListActivity extends Activity {
private ListView listview; //定义一个ListView对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listview =new ListView(this); //实例化一个ListView对象
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, //实例化一个适配器adapter
android.R.layout.simple_expandable_list_item_1, //布局文件:显示一行文字
getData()); //获取数据源(ArrayList集合)
listview.setAdapter(adapter); //装配Adapter到ListView
setContentView(listview); //将list视图显示
}
private List<String> getData() {
// TODO Auto-generated method stub
List<String> data=new ArrayList<String>(); //实例化一个ArrayList集合,用于装载数据
data.add("测试数据1"); //向ArrayList集合中添加元素数据
data.add("测试数据2");
data.add("测试数据3");
data.add("测试数据4");
return data; //返回ArrayList集合对象
}
}
分析:
(1) getData()
(2) List<String>
(3) List<String> data=new ArrayList<String>()
效果:
5.SimpleAdapter实例分析
与ArrayAdapter不同的是,simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等等。一般情况下,我们都是利用Map哈希表作为数据源,通过键到组件Id的映射实现列表项内容。
(1)开发基本思路
a.装配适配器,将Map键数据资源映射到Id所对应的组件上;
SimpleAdapter adapter =new SimpleAdapter(this, //上下文
getData(), //获取list数据集
R.layout.simple, //指定布局文件
new String[]{"img","title1","info"}, //Map集合键
new int[]{R.id.img,R.id.title1,R.id.info});//界面组件Id
b.实现一个Map集合,并将map对象添加
ArrayList中
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>(); //实例化一个ArrayList对象,
Map<String,Object> map=new HashMap<String,Object>(); //设置列表第一项标题与图标(使用Map)
c.
将ArrayAdapter适用于ListActivity的ListView
setListAdapter(adapter);
(2)源代码分析
SimpleAdapterActivity.java
package com.example.android_sampleadapter_1;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.SimpleAdapter;
public class SimpleAdapterActivity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1.装配适配器,并绑定数据到相应的视图
SimpleAdapter adapter =new SimpleAdapter(this, //上下文
getData(), //获取list数据集
R.layout.simple, //指定布局文件
new String[]{"img","title1","info"}, //Map集合键
new int[]{R.id.img,R.id.title1,R.id.info});//界面组件Id
//2.显示视图
setListAdapter(adapter);
}
//3.Map数据集:HashMap构成的List,list的每一节对应ListView的每一行
//HashMap的每个键值数据映射到布局文件中对应id的组件上
private List<Map<String,Object>> getData() {
// TODO Auto-generated method stub
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>(); //实例化一个ArrayList对象,
Map<String,Object> map=new HashMap<String,Object>(); //设置列表第一项标题与图标(使用Map)
map.put("img", R.drawable.a);
map.put("title1", "华为荣耀");
map.put("info", "学人家玩抢购,真TM坑爹!");
list.add(map); //将一个map对象添加到列表中
map=new HashMap<String,Object>();
map.put("img", R.drawable.b);
map.put("title1", "中国移动");
map.put("info", "god knows");
list.add(map); //将一个map对象添加到列表中
map=new HashMap<String,Object>();
map.put("img", R.drawable.c);
map.put("title1", "中兴");
map.put("info", "手机还不错,只是要死不活的");
list.add(map); //将一个map对象添加到列表中
map=new HashMap<String,Object>();
map.put("img", R.drawable.d);
map.put("title1", "魅族4");
map.put("info", "有点贵!");
list.add(map); //将一个map对象添加到列表中
return list;
}
}
分析:
使用simpleAdapter的数据用一般都是HashMap构成的List,list的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局simple.xml。下面做适配,new一个SimpleAdapter参数一次是:this,布局文件(vlist.xml),HashMap的
title 和 info,img,布局文件的组件id,title,info,img。布局文件的各组件分别映射到HashMap的各元素上,完成适配。
simple.xml-列表项布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"/>
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView
android:id="@+id/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000" android:textSize="22sp"/>
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF000000" android:textSize="13sp"/>
</LinearLayout>
</LinearLayout>
6.SimpleAdapter实例分析
package com.example.android_simplecuroradapter;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListAdapter;
public class SimpleCursorActivity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1.获得一个指向系统通讯录数据库的CurSor对象获得数据来源
Cursor cur=getContentResolver().query(People.CONTENT_URI, null, null, null, null);
startManagingCursor(cur);
//2.实例化列表适配器
ListAdapter adapter=new SimpleCursorAdapter(this,android.R.layout.simple_expandable_list_item_1,cur,new
String[] {People.NAME},new int[] {android.R.id.text1});
//3.显示视图
setListAdapter(adapter);
}
}
分析:
一定要以数据库作为数据源的时候,才能使用SimpleCursorAdapter,这里特别需要注意的一点是:不要忘了在AndroidManifest.xml文件中加入权限
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
效果:
参考: