0%

ListView的使用与调优

Android开发 | ListView 的使用与调优

本节我们将讲述如何使用ListView 的使用与调优,配合着视频 一起”下饭”,饭更香 !!

1. ListView 是什么?

image-20210319154311244

2.ListView的基本使用

  1. 首先在XML布局界面中引入ListView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?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">

    <ListView
    android:id="@+id/lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
    </LinearLayout>
  2. 定义ListViewitem的样式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?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">
    <TextView
    android:id="@+id/tv"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="30sp"/>
    </LinearLayout>
  3. ListView中的item定义为一个类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Bean {
    private String name;

    public Bean(String name) {
    this.name = name;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }
  4. 准备数据 通过List<Bean>来存放数据

    1
    2
    3
    4
    5
    6
    private List<Bean> data = new ArrayList<>();
    for (int i = 0; i < 100; i++)
    {
    Bean bean = new Bean("LittleStone" + i);
    data.add(bean);
    }
  5. 数据不能直接添加到ListView中,而是通过一个中间件Adapter,所以我们还需要自定义个Myadapter类(继承BaseAdapter)来包裹数据, 最重要的函数

    getView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class Myadapter extends BaseAdapter {
    private List<Bean> data;
    private Context context;
    private String TAG = "Myadapter";

    public Myadapter(Context context, List<Bean> data) {
    this.context = context;
    this.data = data;
    }

    @Override
    public int getCount() {
    return data.size();
    }

    @Override
    public Object getItem(int position) {
    return data.get(position);
    }

    @Override
    public long getItemId(int position) {
    return position;
    }

    @Override
    /**
    * 每个item出现在屏幕中就会被调用
    */
    public View getView(int position, View convertView, ViewGroup parent) {
    convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
    TextView textView = convertView.findViewById(R.id.tv);
    textView.setText(data.get(position).getName());
    Log.e(TAG, "getView: "+position );
    return convertView;
    }


    }
  6. AdapterListView绑定,

    1
    2
    ListView listView = findViewById(R.id.lv);
    listView.setAdapter(new Myadapter(this, data));

3. ListView的调优过程

3.1使用convertView来记录缓存
  1. getview函数形参中的convertView 记录了之前创建的convertView,当第一次打开Android的ListView初始化时候,在Adapter中此时的convertView无疑均是空的,假设屏幕可以放m条item,那么会创建m+1个convertView

  2. convertView发生作用的地方,就是当ListView在向上/向下滑动过程中,convertView缓存和复用机制才发挥出来。比如当手指在屏幕自下往上翻动ListView时候,此时ListView头部的item将滚出设备屏幕,而底部的新item将加载出来,此时convertView的复用机制将发挥作用。由于此前在ListView初始化阶段已经创建了九个全新的convertView,Android系统将之前ListView初始化阶段创建的m个全新convertView都缓存起来,现在,由于ListView的上下翻动,顶部和底部之前显示的item滚出设备屏幕不可见,Android系统要么完全回收这些convertView,要么复用这些convertView。ListView的item有一个共同点:在大多数情况下,这些item的View( **指的是 布局是相同的 都是一个item xml文件)**是相同的,所以,明智的做法是继续复用,这样无疑会提高系统加载性能,要知道每一次创建新的convertView,是有一定系统开销的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    if (convertView == null) {
    convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
    Log.i(TAG, "位置" + position + ",创建convertView" + "index=" + index);
    index += 1;
    } else {
    Log.i(TAG, "位置" + position + "使用缓存技术");
    }
    TextView textView = convertView.findViewById(R.id.tv);
    textView.setText(data.get(position).getName());
    // Log.e(TAG, "getView: " + position);
    return convertView;

    打印的日志 除了一开始屏幕14+1个 创建convertView 其余的都会使用缓存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    com.littlestone.mylistview I/Myadapter: 位置0,创建convertViewindex=0
    com.littlestone.mylistview I/Myadapter: 位置1,创建convertViewindex=1
    com.littlestone.mylistview I/Myadapter: 位置2,创建convertViewindex=2
    com.littlestone.mylistview I/Myadapter: 位置3,创建convertViewindex=3
    com.littlestone.mylistview I/Myadapter: 位置4,创建convertViewindex=4
    com.littlestone.mylistview I/Myadapter: 位置5,创建convertViewindex=5
    com.littlestone.mylistview I/Myadapter: 位置6,创建convertViewindex=6
    com.littlestone.mylistview I/Myadapter: 位置7,创建convertViewindex=7
    com.littlestone.mylistview I/Myadapter: 位置8,创建convertViewindex=8
    com.littlestone.mylistview I/Myadapter: 位置9,创建convertViewindex=9
    com.littlestone.mylistview I/Myadapter: 位置10,创建convertViewindex=10
    com.littlestone.mylistview I/Myadapter: 位置11,创建convertViewindex=11
    com.littlestone.mylistview I/Myadapter: 位置12,创建convertViewindex=12
    com.littlestone.mylistview I/Myadapter: 位置13,创建convertViewindex=13
    com.littlestone.mylistview I/Myadapter: 位置14,创建convertViewindex=14
    com.littlestone.mylistview I/Myadapter: 位置15,创建convertViewindex=15
    com.littlestone.mylistview I/Myadapter: 位置0使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置15使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置16使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置17使用缓存技术
    .........
    com.littlestone.mylistview I/Myadapter: 位置77使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置93使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置94使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置95使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置96使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置97使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置98使用缓存技术
    com.littlestone.mylistview I/Myadapter: 位置99使用缓存技术

3.2 使用 自定义ViewHolder类来避免多次findViewByid

我们发现 findviewByid会被多次调用,这也是非常耗时的,通过使用一个自定义的内部类Holder里面放 item.xml的所需要控件 作为成员变量,在得到convertView后调用 convertViewsetTag()Holder 作为形参放入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Holder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
holder = new Holder();
holder.textView = convertView.findViewById(R.id.tv);
convertView.setTag(holder);
Log.i(TAG, "位置" + position + ",创建convertView" + "index=" + index);
index += 1;
} else {
Log.i(TAG, "位置" + position + "使用缓存技术");
holder = (Holder) convertView.getTag();
}
holder.textView.setText(data.get(position).getName());
return convertView;


public class Holder {
private TextView textView;
}