Android ListView 详解
介绍
“List view” 是一种用户界面设计中的布局方式,它通过列表的形式展示信息,是一种将信息组织为条目(通常是行)的视图形式,每一项条目都是列表中的一行,可能包含文本、图像或其他元素。
基本使用
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
activity
public class MainActivity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<String> fruits =new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("普通");
fruits.add("西瓜");
//为listview绑定控件
listView =findViewById(R.id.listview);
//为listview绑定适配器
listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,fruits));
}
}
以上是最基本的使用方法
自定义适配器
现在使用listview来显示学生列表
entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
String name;
String age;
String sex;
String image;
}
/*
@Data
@AllArgsConstructor
@NoArgsConstructor
这些注释需要添加依赖
implementation 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
如果不添加依赖自己写get、set方法也可以
*/
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
为listview绘制适配界面
在layout目录下创建layout_student_list.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">
<TextView
android:id="@+id/name"
android:layout_marginHorizontal="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/sex"
android:layout_marginHorizontal="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/age"
android:layout_marginHorizontal="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
为listview创建适配器
public class MyListAdapter extends BaseAdapter {
Context context;
List<Student> students;
public MyListAdapter(Context context, List<Student> students){
//初始化
this.context=context;
this.students=students;
}
@Override
public int getCount() {
//返回list数量
return students.size();
}
@Override
public Object getItem(int position) {
//获取每个item
return students.get(position);
}
@Override
public long getItemId(int position) {
//获取下标
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 使用 LayoutInflater 将 layout_student_list 布局文件转换为视图对象。
View viewStudent = LayoutInflater.from(context).inflate(R.layout.layout_student_list, parent, false);
//获得学生对象
Student student = students.get(position);
TextView name = viewStudent.findViewById(R.id.name);
TextView age = viewStudent.findViewById(R.id.age);
TextView sex = viewStudent.findViewById(R.id.sex);
//将数据一一添加到布局中。
name.setText(student.getName());
age.setText(String.valueOf(student.getAge()));
/*
age.setText();
TextView使用setText方法要使用字符串,非字符串会引发android.content.res.Resources$NotFoundException: String resource ID 异常
非字符串类型请先转为字符串
*/
sex.setText(student.getSex());
return viewStudent ;
}
}
缺点
- 性能开销大:每次
getView
被调用时,findViewById
方法都会被调用,这会导致性能开销增加,特别是在长列表中。 - 视图查找开销:每次
getView
被调用时,都会查找视图组件,增加了 CPU 和内存开销。
使用ViewHolder 优化
使用ViewHolder 对ListView进行优化时只需要修改适配器MyListAdapter代码即可
public class MyListAdapter extends BaseAdapter {
Context context;
List<Student> students;
public MyListAdapter(Context context, List<Student> students){
this.context=context;
this.students=students;
}
@Override
public int getCount() {
return students.size();
}
@Override
public Object getItem(int position) {
return students.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 创建一个 ViewHolder 对象,用于缓存视图组件。
ViewHolder viewHolder = null;
//获得Item位置上的数据。
Student student = students.get(position);
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.layout_student_list, parent, false);
// 创建一个新的 ViewHolder 实例,并将其与 convertView 关联。
viewHolder = new ViewHolder(convertView);
// 将 ViewHolder 对象设置为 convertView 的标签,以便下次重用。
convertView.setTag(viewHolder);
}else{
// 如果 convertView 已经存在,则从 convertView 的标签中获取 ViewHolder 对象。
viewHolder = (ViewHolder) convertView.getTag();
}
// 将当前学生的数据设置到视图中的相应组件。
viewHolder.name.setText(student.getName());
viewHolder.age.setText(String.valueOf(student.getAge()));
viewHolder.sex.setText(student.getSex());
// 返回最终的视图对象。
return convertView;
}
static class ViewHolder{
// 定义用于缓存视图组件的变量。
private final TextView name;
private final TextView age;
private final TextView sex;
public ViewHolder(View itemView){
// 在 itemView 中查找并初始化视图组件。
name = itemView.findViewById(R.id.name);
age = itemView.findViewById(R.id.age);
sex = itemView.findViewById(R.id.sex);
}
}
}
优点:
- 性能优化:通过缓存视图组件,减少了频繁调用
findViewById
的次数,从而降低了 CPU 和内存开销。 - 更清晰的代码:代码更加简洁易懂,减少了在
getView
方法中重复的视图查找逻辑。 - 流畅的滚动体验:提高了
ListView
的滚动性能,使列表滚动更加流畅。