概述
- 数据适配器:由于数据源的多样性及ListView的固定数据格式,需要使用Adapter建立数据源和ListView的动态适配关系。Adapter解耦了数据的来源和显示,降低了程序的耦合性,使之更易扩展。
- ListView的缓存机制:如需同时显示5条数据,滑动时最多会同时显示6条数据,因此系统将加载6个item布局。当向上滑动至第一个item不可见时,该item则进入缓存池。当第7条数据将被显示时,系统会自动从缓存池中取出第一个item。以此类推循环利用,节约了系统资源。
使用
1. 创建MyBean,在onCreate()中准备数据源。
public class MyBean {
public int icon;
public String title;
public String content;
public MyBean(int icon, String title, String content) {
this.icon = icon;
this.title = title;
this.content = content;
}
}
protected void onCreate(Bundle savedInstanceState) {
...
// 准备数据源
List<MyBean> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add(new MyBean(
R.mipmap.ic_launcher,
"Title --- " + i,
"Content --- " + i
));
}
}
2. 创建MyAdapter,在onCreate()中绑定数据
public class MyAdapter extends BaseAdapter {
private List<MyBean> mList;
// 布局装载器对象
private LayoutInflater mInflater;
/**
* @param context 要使用当前Adapter的界面对象
* @param list 关联数据源和适配器
*/
public MyAdapter(Context context, List<MyBean> list) {
mInflater = LayoutInflater.from(context);
mList = list;
}
// 获取ListView需要显示的数据数量
@Override
public int getCount() {
return mList.size();
}
// 获取数据集合中指定索引对应的数据项
@Override
public Object getItem(int i) {
return mList.get(i);
}
// 获取指定行对应item的id
@Override
public long getItemId(int i) {
return i;
}
// 获取每个item的显示内容
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = mInflater.inflate(R.layout.item, null);
}
ImageView icon = (ImageView) view.findViewById(R.id.iv_item_icon);
TextView title = (TextView) view.findViewById(R.id.tv_item_title);
TextView content = (TextView) view.findViewById(R.id.tv_item_content);
MyBean myBean = mList.get(i);
icon.setImageResource(myBean.icon);
title.setText(myBean.title);
content.setText(myBean.content);
return view;
}
}
protected void onCreate(Bundle savedInstanceState) {
...
// 通过Adapter绑定数据
MyAdapter myAdapter = new MyAdapter(this, list);
// 设置ListView显示
listView.setAdapter(myAdapter);
}
针对反复findViewById进行优化 --- ViewHolder
通常我们会对view判空来避免重复创建大量view,优化ListView的item复用,但反复findViewById寻找控件效率仍有可提升的空间。下面将通过ViewHolder缓存显示数据的视图,进一步优化Adapter。
package com.eczom.myadapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class MyAdapter extends BaseAdapter {
private List<MyBean> mList;
// 布局装载器对象
private LayoutInflater mInflater;
/**
* @param context 要使用当前Adapter的界面对象
* @param list 关联数据源和适配器
*/
public MyAdapter(Context context, List<MyBean> list) {
mInflater = LayoutInflater.from(context);
mList = list;
}
// 获取ListView需要显示的数据数量
@Override
public int getCount() {
return mList.size();
}
// 获取数据集合中指定索引对应的数据项
@Override
public Object getItem(int i) {
return mList.get(i);
}
// 获取指定行对应item的id
@Override
public long getItemId(int i) {
return i;
}
// 获取每个item的显示内容
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// 对view判空
if (view == null) {
viewHolder = new ViewHolder();
view = mInflater.inflate(R.layout.item, null);
// 通过ViewHolder对象获取对应控件
viewHolder.icon = (ImageView) view.findViewById(R.id.iv_item_icon);
viewHolder.title = (TextView) view.findViewById(R.id.tv_item_title);
viewHolder.content = (TextView) view.findViewById(R.id.tv_item_content);
// 通过setTag()绑定ViewHolder和view
view.setTag(viewHolder);
} else {
// 通过getTag()获取已绑定的ViewHolder
viewHolder = (ViewHolder) view.getTag();
}
// 绑定当前数据项和item
MyBean myBean = mList.get(i);
viewHolder.icon.setImageResource(myBean.icon);
viewHolder.title.setText(myBean.title);
viewHolder.content.setText(myBean.content);
return view;
}
// 创建内部类ViewHolder
class ViewHolder {
public ImageView icon;
public TextView title;
public TextView content;
}
}