在 Android 开发中,Adapter 是连接数据源(如数组、列表、数据库)与 UI 组件(如 ListView
、RecyclerView
、Spinner
)的桥梁。以下从不同角度详细介绍 Adapter 及其 Java 实现。
一、Adapter 的核心概念
- 作用
将数据(如字符串、对象)动态绑定到 UI 组件,每个数据项生成对应的视图(View
)。 - 核心方法
•getCount()
: 返回数据项总数。
•getItem(int position)
: 返回特定位置的数据项。
•getItemId(int position)
: 返回数据项的唯一 ID。
•getView(int position, View convertView, ViewGroup parent)
: 生成数据项对应的视图。
二、常见 Adapter 类型及示例
1. ArrayAdapter
• 用途:将数组或列表数据绑定到 ListView
或 Spinner
。
• 特点:内置简单布局,支持自定义布局。
// 示例:绑定字符串数组到 ListView
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.list_view);
String[] data = {"Apple", "Banana", "Cherry"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1, // 内置布局
data
);
listView.setAdapter(adapter);
}
}
2. BaseAdapter(自定义 Adapter)
• 用途:完全自定义列表项布局和逻辑。
• 关键优化:使用 ViewHolder
减少 findViewById
调用。
// 示例:自定义 Adapter 显示图标和文本
public class CustomAdapter extends BaseAdapter {
private Context context;
private List<Item> items;
public CustomAdapter(Context context, List<Item> items) {
this.context = context;
this.items = items;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context)
.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.image = convertView.findViewById(R.id.image_view);
holder.text = convertView.findViewById(R.id.text_view);
convertView.setTag(holder); // 缓存 ViewHolder
} else {
holder = (ViewHolder) convertView.getTag();
}
Item item = items.get(position);
holder.image.setImageResource(item.getImageResId());
holder.text.setText(item.getText());
return convertView;
}
static class ViewHolder {
ImageView image;
TextView text;
}
}
3. RecyclerView.Adapter
• 用途:现代列表组件 RecyclerView
的 Adapter,支持更灵活的布局和动画。
• 关键特性:强制使用 ViewHolder
模式,分离布局管理器(LayoutManager
)和装饰(ItemDecoration
)。
// 示例:RecyclerView Adapter
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
private List<String> data;
public MyRecyclerAdapter(List<String> data) {
this.data = data;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.textView.setText(data.get(position));
}
@Override
public int getCount() {
return data.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_view);
}
}
}
三、Adapter 的优化技巧
- 复用
convertView
在getView()
中复用convertView
减少视图创建开销。 - ViewHolder 模式
缓存视图组件,避免重复调用findViewById
。 - 局部更新数据
使用notifyItemChanged(int position)
代替notifyDataSetChanged()
(针对RecyclerView
)。
四、高级用法
1. 多布局类型
• 重写 getItemViewType()
和 getViewTypeCount()
(对 ListView
)或 RecyclerView.Adapter
的 getItemViewType()
。
// 示例:RecyclerView 多布局类型
@Override
public int getItemViewType(int position) {
return (data.get(position).isHeader()) ? TYPE_HEADER : TYPE_ITEM;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
// 加载头部布局
} else {
// 加载普通项布局
}
}
2. 点击事件处理
• 在 Adapter 中定义接口回调。
// 示例:定义点击监听器
public interface OnItemClickListener {
void onItemClick(int position);
}
public class CustomAdapter extends BaseAdapter {
private OnItemClickListener listener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// ...
convertView.setOnClickListener(v -> {
if (listener != null) {
listener.onItemClick(position);
}
});
return convertView;
}
}
五、Adapter 的生命周期与数据更新
- 数据更新
•ArrayAdapter
: 修改数据源后调用notifyDataSetChanged()
。
•RecyclerView.Adapter
: 使用DiffUtil
高效更新数据。 - 内存管理
• 避免在 Adapter 中持有Activity
或Fragment
的引用(防止内存泄漏)。
• 使用弱引用或传递ApplicationContext
。
六、最佳实践
- 优先使用
RecyclerView
替代ListView
和GridView
,支持更灵活的布局和动画。 - 分离关注点
将数据操作(如排序、过滤)放在 Adapter 外部。 - 使用数据绑定库
通过Data Binding
或View Binding
简化findViewById
调用。