ListView缓存机制
要想优化ListView首先要了解它的工作原理,列表的显示需要三个元素:ListView、Adapter、显示的数据;
这里的Adapter就是用到了适配器模式,不管传入的是什么View在ListView中都能显示出来。
下面简单说下上图的原理:
1、如果你有几千几万甚至更多的选项(item)时,其中只有可见的项目(满屏显示的Item数目)存在内存(说的优化就是说在内存中的优化!)中,其他的在Recycler中
2、ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的,第一次都是为空的,只要显示过了convertView都不为空,会保存在Recycler中
3、当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值 了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图,省去了inflate和findViewById的 时间,性能就得到了优化。
了解了它的工作原理后,我们就可以重复利用convertView,只要不为空就直接使用,改变它的内容就行了。
使用ListView的时候都会搭配一个Adapter,为了使得性能更优,ListView会缓存行item(某行对应的View)。ListView通过Adapter的getView函数获得每行的item。
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
package com.dzt.listviewdemo; import java.util.ArrayList; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private ListAdapter adapter; private ListView lv = null ; private ArrayList<string> list = new ArrayList<string>(); @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv = (ListView) findViewById(R.id.lv_list); adapter = new ListAdapter(); for ( int i = 0 ; i < 100 ; i++) { list.add(item + i); } lv.setAdapter(adapter); } private class ListAdapter extends BaseAdapter { private LayoutInflater mInflater; ListAdapter() { mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem( int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId( int position) { // TODO Auto-generated method stub return position; } @Override public View getView( int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub System.out.println(getView + position + + convertView); viewHolder holder = null ; if (convertView == null ) { convertView = mInflater.inflate(R.layout.item, null ); holder = new viewHolder(); holder.text = (TextView) convertView.findViewById(R.id.tv_text); holder.image = (ImageView) convertView .findViewById(R.id.iv_img); convertView.setTag(holder); } else { holder = (viewHolder) convertView.getTag(); } holder.text.setText(list.get(position)); if (position % 2 == 0 ) { holder.image.setImageResource(R.drawable.ic_launcher); } else { holder.image.setImageResource(R.drawable.icon); } return convertView; } } /** * 使用一个类来保存Item中的元素 * * @author Administrator * */ public static class viewHolder { public TextView text; public ImageView image; } } </string></string> |
运行效果
第一次打印的结果convertView都是为null
滑动ListView后的打印
从上面的打印消息可以看出,Recycler中会保存七个convertView对象用来显示Item,不管你有上千个Item,也只会创建显示满屏的convertView,这就大大节省了内存,对viewHolder的Tag的使用也大大节省了性能开销