ListView是用来交互和展示数据的,但是数据的类型很多,如果让ListView为每一种数据都进行适配的话那么ListView是比较臃肿的,所以就需要Adapter去帮助我们适配数据源。
Adapter是一个接口,Adapter常用的实现类如下:
ArrayAdapter: 简单,易用的Adapter,通常用于将数组或者List集合的多个值包装成多个列表项。
SimpleAdapter: 并不简单,功能强大的Adapter,可用于将List集合的多个对象包装成多个列表项。
SimpleCursorAdapter:与SimpleAdapter基本相似,只是用于包装Cursor提供的数据。
BaseAdapter: 通常用于被扩展。扩展BaseAdapter可以对各列表项进行最大限度的定制。
listView与ArrayAdapter
使用步骤:
1. 创建并绑定ListView。
2. 创建ArrayAdapter。
3. 设置ListView的Adapter。
ArrayAdapter有两个构造方法:
ArrayAdapter(Context context, int textViewResourceId, List objects)
ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)
其中resource用于布局文件资源。textViewResourceId设置TextView样式。
textViewResourceId常用的参数为:
simple_list_item_1: 每个列表项都是一个普通的TextView。
simple_list_item_2: 有两个TextView,分两行显示。
simple_list_item_multiple_choice: 每个列表项都带多选框。
simple_list_item_single_choice :每个列表项都带单选框。
示例程序
public class MainActivity extends Activity {
private String[] data = {"apple", "banana", "orange", "watermelon", "pear"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1, data);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}
xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
ListView与SimpleAdapter
通过ArrayAdapter实现Adapter虽然简单,但是ArrayAdapter得功能比较有限。如果需要实现更复杂的功能就需要使用SimpleAdapter了。
SimpleAdapter的构造方法为:
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
@LayoutRes int resource, String[] from, @IdRes int[] to)
第二个参数: 该集合中每一个Map<String, ?>
对象生成一个列表项。
第三个参数: 指定一个界面布局的ID。
第四个参数: 决定提取Map<String , ?>
中的对象的哪些key对应的value来生成列表项。
第五个参数: 决定填充哪些组件。
示例程序
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
</LinearLayout>
新建一个simple_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/header"
android:paddingLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:textSize="20dp"
android:textColor="#f0f"
android:paddingLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/desc"
android:textSize="14dp"
android:paddingLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
MainActivity
public class MainActivity extends Activity {
private String[] name = {"apple", "banana", "orange", "watermelon", "pear"};
private String[] descs = {"苹果好吃", "香蕉好吃", "橘子好处", "西瓜好吃", "梨好吃"};
//随便找的图标
private int[] imageId = new int[]{R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
List<Map<String, Object>> listItems = new ArrayList<>();
for (int i = 0; i < name.length; i++) {
Map<String, Object> listItem = new HashMap<>();
listItem.put("header", imageId[i]);
listItem.put("name", name[i]);
listItem.put("desc", descs[i]);
listItems.add(listItem);
}
SimpleAdapter simpleAdapter = new SimpleAdapter(this, listItems, R.layout.simple_item,
new String[]{"name", "header", "desc"},
new int[]{R.id.name, R.id.header, R.id.desc});
ListView list = (ListView) findViewById(R.id.list_view);
list.setAdapter(simpleAdapter);
}
}
扩展BaseAdapter
扩展BaseAdapter需要重写4个方法。
getCount():该方法的返回值控制该Adapter将会包含多少个列表项。
getItem(int position):该方法的返回值决定第position处的列表项的内容。
getItemId(int position):该方法的返回值决定第position处的列表项的ID。
getView(int position, View convertView, ViewGroup parent):这里最重要的方法,该方法的返回值决定第position处的列表项组件。
public class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return 0;
}
@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) {
return null;
}
}
getView的优化
要理解getView的优化首先应理解 Recycle机制。这里推荐郭霖的 Android ListView工作原理完全解析,带你从源码的角度彻底理解
没有任何优化:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item, null);
ImageView img = (ImageView)item.findViewById(R.id.img)
TextView title = (TextView)item.findViewById(R.id.title);
TextView info = (TextView)item.findViewById(R.id.info);
img.setImageResource(R.drawable.ic_launcher);
title.setText("Hello");
info.setText("world");
return item;
}
每加载一个数据时都会重新创建View和绑定资源操作。一旦数据量多的时候会严重影响性能。
优化一:利用缓存中的View也就是convertView
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
{
convertView = mInflater.inflate(R.layout.list_item, null);
}
ImageView img = (ImageView)convertView.findViewById(R.id.img)
TextView title = (TextView)convertView.findViewById(R.id.title);
TextView info = (TextView)ConvertView.findViewById(R.id.info);
img.setImageResource(R.drawable.ic_launcher);
title.setText("Hello");
info.setText("world");
return convertView;
}
优化二:利用静态类优化绑定资源的操作
//在外面先定义,ViewHolder静态类
static class ViewHolder
{
public ImageView img;
public TextView title;
public TextView info;
}
//然后重写getView
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.list_item, null);
holder.img = (ImageView)item.findViewById(R.id.img)
holder.title = (TextView)item.findViewById(R.id.title);
holder.info = (TextView)item.findViewById(R.id.info);
convertView.setTag(holder);
}else
{
holder = (ViewHolder)convertView.getTag();
holder.img.setImageResource(R.drawable.ic_launcher);
holder.title.setText("Hello");
holder.info.setText("World");
}
return convertView;
}
示例程序
activicy_main和simple_item直接用simpleAdapter示例程序的。
MainActivity:
public class MainActivity extends Activity {
private List<Map<String, Object>> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
data = getData();
MyAdapter myAdapter = new MyAdapter(this);
ListView list = (ListView) findViewById(R.id.list_view);
list.setAdapter(myAdapter);
}
private List<Map<String, Object>> getData(){
List<Map<String, Object>> listItems = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Map<String, Object> listItem = new HashMap<>();
listItem.put("header", R.drawable.ic_launcher);
listItem.put("name", i + "Android机器人");
listItem.put("desc", "Android机器人");
listItems.add(listItem);
}
return listItems;
}
static class ViewHolder{
public ImageView header;
public TextView name;
public TextView desc;
}
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public MyAdapter(Context context){
this.mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return 20;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null){
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.simple_item, null);
holder.header = (ImageView) convertView.findViewById(R.id.header);
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.desc = (TextView) convertView.findViewById(R.id.desc);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.header.setBackgroundResource((Integer) data.get(position).get("header"));
holder.name.setText((String) data.get(position).get("name"));
holder.desc.setText((String) data.get(position).get("desc"));
return convertView;
}
}
}
参考书籍博客
《第一行代码》
《Android疯狂讲义》第三版
Android ListView工作原理完全解析,带你从源码的角度彻底理解
android应用开发全程实录-你有多熟悉listview?
android ListView详解
Android杂谈–ListView之BaseAdapter的使用
博客内容是我阅读以上资料加上自己的理解所得,有部分摘抄自以上资料,侵删。