现在的位置: 首页 > 综合 > 正文

listview 分析

2013年03月29日 ⁄ 综合 ⁄ 共 7607字 ⁄ 字号 评论关闭

 

ListView 和 Adapter 的基础

工作原理:

  1. ListView 针对List中每个item,要求 adapter “给我一个视图” (getView)。
  2. 一个新的视图被返回并显示

如果我们有上亿个项目要显示怎么办?为每个项目创建一个新视图?NO!这不可能!

实际上Android为你缓存了视图。

Android中有个叫做Recycler的构件,下图是他的工作原理:

  1. 如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。
  2. ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。
  3. 当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图。

请看下面的示例代码,这里在getView中使用了System.out进行输出

01 public
class
MultipleItemsList extends
ListActivity {
02    
03     private
MyCustomAdapter mAdapter;
04    
05     @Override
06     public
void onCreate(Bundle savedInstanceState) {
07         super.onCreate(savedInstanceState);
08         mAdapter =
new MyCustomAdapter();
09         for
(int
i =
0; i <
50; i++) {
10             mAdapter.addItem("item "
+ i);
11         }
12         setListAdapter(mAdapter);
13     }
14    
15     private
class MyCustomAdapter
extends BaseAdapter {
16    
17         private
ArrayList mData = new
ArrayList();
18         private
LayoutInflater mInflater;
19    
20         public
MyCustomAdapter() {
21             mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
22         }
23    
24         public
void addItem(final
String item) {
25             mData.add(item);
26             notifyDataSetChanged();
27         }
28    
29         @Override
30         public
int getCount() {
31             return
mData.size();
32         }
33    
34         @Override
35         public
String getItem(int
position) {
36             return
mData.get(position);
37         }
38    
39         @Override
40         public
long getItemId(int
position) {
41             return
position;
42         }
43    
44         @Override
45         public
View getView(int
position, View convertView, ViewGroup parent) {
46             System.out.println("getView "
+ position + " "
+ convertView);
47             ViewHolder holder =
null;
48             if
(convertView == null) {
49                 convertView = mInflater.inflate(R.layout.item1,
null);
50                 holder =
new ViewHolder();
51                 holder.textView = (TextView)convertView.findViewById(R.id.text);
52                 convertView.setTag(holder);
53             }
else {
54                 holder = (ViewHolder)convertView.getTag();
55             }
56             holder.textView.setText(mData.get(position));
57             return
convertView;
58         }
59    
60     }
61    
62     public
static class
ViewHolder {
63         public
TextView textView;
64     }
65 }

 

执行程序,然后在Logcat中查看日志

 

getView 被调用 9 次 ,convertView 对于所有的可见项目是空值(如下)

 

02-05
13:47:32.559: INFO/System.out(947):
getView
0 null
02-05
13:47:32.570: INFO/System.out(947):
getView
1 null
02-05
13:47:32.589: INFO/System.out(947):
getView
2 null
02-05
13:47:32.599: INFO/System.out(947):
getView
3 null
02-05
13:47:32.619: INFO/System.out(947):
getView
4 null
02-05
13:47:32.629: INFO/System.out(947):
getView
5 null
02-05
13:47:32.708: INFO/System.out(947):
getView
6 null
02-05
13:47:32.719: INFO/System.out(947):
getView
7 null
02-05
13:47:32.729: INFO/System.out(947):
getView
8 null

 

然后稍微向下滚动List,直到item10出现:

 

convertView仍然是空值,因为recycler中没有视图(item1的边缘仍然可见,在顶端)

 

02-05
13:48:25.169: INFO/System.out(947):
getView
9 null

 

再滚动List

 

convertView不是空值了!item1离开屏幕到Recycler中去了,然后item11被创建

 

02-05
13:48:42.879: INFO/System.out(947):
getView
10 android.widget.LinearLayout@437430f8

 

再滚动:

02-05
14:01:31.069: INFO/System.out(947):
getView
11 android.widget.LinearLayout@437447d0
02-05
14:01:31.142: INFO/System.out(947):
getView
12 android.widget.LinearLayout@43744ff8
02-05
14:01:31.279: INFO/System.out(947):
getView
13 android.widget.LinearLayout@43743fa8
02-05
14:01:31.350: INFO/System.out(947):
getView
14 android.widget.LinearLayout@43745820
02-05
14:01:31.429: INFO/System.out(947):
getView
15 android.widget.LinearLayout@43746048
02-05
14:01:31.550: INFO/System.out(947):
getView
16 android.widget.LinearLayout@43746870
02-05
14:01:31.669: INFO/System.out(947):
getView
17 android.widget.LinearLayout@43747098
02-05
14:01:31.839: INFO/System.out(947):
getView
18 android.widget.LinearLayout@437478c0
02-05
14:03:30.900: INFO/System.out(947):
getView
19 android.widget.LinearLayout@43748df0
02-05
14:03:32.069: INFO/System.out(947):
getView
20 android.widget.LinearLayout@437430f8

convertView 如我们所期待的非空了,在item11离开屏幕之后,它的视图(@437430f8)作为convertView容纳item21了

不同的项目布局(item layout)

我们再举一个稍微复杂的例子,在上例的list中加入一些分隔线

你需要做这些:

  1. 重(@Override)写 getViewTypeCount() – 返回你有多少个不同的布局
  2. 重写 getItemViewType(int) – 由position返回view type id
  3. 根据view item的类型,在getView中创建正确的convertView

以下是代码:

 

001 public
class
MultipleItemsList extends
ListActivity {
002    
003     private
MyCustomAdapter mAdapter;
004    
005     @Override
006     public
void onCreate(Bundle savedInstanceState) {
007         super.onCreate(savedInstanceState);
008         mAdapter =
new MyCustomAdapter();
009         for
(int
i =
1; i <
50; i++) {
010             mAdapter.addItem("item "
+ i);
011             if
(i % 4
==
0) {
012                 mAdapter.addSeparatorItem("separator "
+ i);
013             }
014         }
015         setListAdapter(mAdapter);
016     }
017    
018     private
class MyCustomAdapter
extends BaseAdapter {
019    
020         private
static final
int
TYPE_ITEM = 0;
021         private
static final
int
TYPE_SEPARATOR = 1;
022         private
static final
int
TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;
023    
024         private
ArrayList mData = new
ArrayList();
025         private
LayoutInflater mInflater;
026    
027         private
TreeSet mSeparatorsSet = new
TreeSet();
028    
029         public
MyCustomAdapter() {
030             mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
031         }
032    
033         public
void addItem(final
String item) {
034             mData.add(item);
035             notifyDataSetChanged();
036         }
037    
038         public
void addSeparatorItem(final
String item) {
039             mData.add(item);
040             // save separator position
041             mSeparatorsSet.add(mData.size() -
1);
042             notifyDataSetChanged();
043         }
044    
045         @Override
046         public
int getItemViewType(int
position) {
047             return
mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
048         }
049    
050         @Override
051         public
int getViewTypeCount() {
052             return
TYPE_MAX_COUNT;
053         }
054    
055         @Override
056         public
int getCount() {
057             return
mData.size();
058         }
059    
060         @Override
061         public
String getItem(int
position) {
062             return
mData.get(position);
063         }
064    
065         @Override
066         public
long getItemId(int
position) {
067             return
position;
068         }
069    
070         @Override
071         public
View getView(int
position, View convertView, ViewGroup parent) {
072             ViewHolder holder =
null;
073             int
type = getItemViewType(position);
074             System.out.println("getView "
+ position + " "
+ convertView + " type = "
+ type);
075             if
(convertView == null) {
076                 holder =
new ViewHolder();
077                 switch
(type) {
078                     case
TYPE_ITEM:
079                         convertView = mInflater.inflate(R.layout.item1,
null);
080                         holder.textView = (TextView)convertView.findViewById(R.id.text);
081                         break;
082                     case
TYPE_SEPARATOR:
083                         convertView = mInflater.inflate(R.layout.item2,
null);
084                         holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);
085                         break;
086                 }
087                 convertView.setTag(holder);
088             }
else {
089                 holder = (ViewHolder)convertView.getTag();
090             }
091             holder.textView.setText(mData.get(position));
092             return
convertView;
093         }
094    
095     }
096    
097     public
static class
ViewHolder {
098         public
TextView textView;
099     }
100 }

 

运行程序,你会看到每4个item一个分割线

看看日志,无异常,所有的convertView都是空的

 

抱歉!评论已关闭.