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都是空的

02-05 15:19:03.080: INFO/System.out(1035): getView 0 null type = 0
02-05 15:19:03.112: INFO/System.out(1035): getView 1 null type = 0
02-05 15:19:03.130: INFO/System.out(1035): getView 2 null type = 0
02-05 15:19:03.141: INFO/System.out(1035): getView 3 null type = 0
02-05 15:19:03.160: INFO/System.out(1035): getView 4 null type = 1
02-05 15:19:03.170: INFO/System.out(1035): getView 5 null type = 0
02-05 15:19:03.180: INFO/System.out(1035): getView 6 null type = 0
02-05 15:19:03.190: INFO/System.out(1035): getView 7 null type = 0
02-05 15:19:03.210: INFO/System.out(1035): getView 8 null type = 0
02-05 15:19:03.210: INFO/System.out(1035): getView 9 null type = 1

滚动list:

02-05 15:19:54.160: INFO/System.out(1035): getView 10 null type = 0
02-05 15:19:57.440: INFO/System.out(1035): getView 11 android.widget.LinearLayout@43744528 type = 0
02-05 15:20:01.310: INFO/System.out(1035): getView 12 android.widget.LinearLayout@43744eb0 type = 0
02-05 15:20:01.880: INFO/System.out(1035): getView 13 android.widget.LinearLayout@437456d8 type = 0
02-05 15:20:02.869: INFO/System.out(1035): getView 14 null type = 1
02-05 15:20:06.489: INFO/System.out(1035): getView 15 android.widget.LinearLayout@43745f00 type = 0
02-05 15:20:07.749: INFO/System.out(1035): getView 16 android.widget.LinearLayout@43747170 type = 0
02-05 15:20:10.250: INFO/System.out(1035): getView 17 android.widget.LinearLayout@43747998 type = 0
02-05 15:20:11.661: INFO/System.out(1035): getView 18 android.widget.LinearLayout@437481c0 type = 0
02-05 15:20:13.180: INFO/System.out(1035): getView 19 android.widget.LinearLayout@437468a0 type = 1
02-05 15:20:16.900: INFO/System.out(1035): getView 20 android.widget.LinearLayout@437489e8 type = 0
02-05 15:20:25.690: INFO/System.out(1035): getView 21 android.widget.LinearLayout@4374a8d8 type = 0

convertView对于分割线是空的,直到第一个分割线可见,当其离开屏幕,视图去到Recycler并且convertView开始起作用。

本文翻译自http://android.amberfog.com/?p=296

代码下载:MultipleItemsList.zip – source code

转自:http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html

[Android] ListView中getView的原理+如何在ListView中放置多个item相关推荐

  1. java中求组快速排序函数,如何在Java中实现快速排序?

    成为专业认证的快速排序是一种分而治之的算法.在分治算法的设计范式中,我们先递归地将问题分解成子问题,然后再求解子问题,最后将求解结果进行组合得到最终结果.在本文中,我们将重点讨论Java中的快速排序本 ...

  2. excel中去重计数_如何在Excel中计数

    excel中去重计数 There are lots of different ways to count things in Excel – maybe you need to count the n ...

  3. html中section与div,如何在html中的section标签内包含div标签

    我正在制作一个完整版块的页面网站,如this.每个页面都有自己的标签.目前我的网页有4个部分(呈现不同的背景颜色).如何在html中的section标签内包含div标签 我的第一部分有一个容器div, ...

  4. python中range 10 0_如何在python中使用range方法

    如何在python中使用range方法 发布时间:2021-01-05 16:55:23 来源:亿速云 阅读:94 作者:Leah 如何在python中使用range方法?很多新手对此不是很清楚,为了 ...

  5. css中 media的用法,如何在css中正确使用@media

    如何在css中使用@media作为特定分辨率?所以我想让我的侧栏更改取决于用户分辨率,所以我使用@media.如何在css中正确使用@media 这是示例代码: @media (max-width: ...

  6. java 中覆 写tostring_如何在Java中正确覆盖toString()?

    如何在Java中正确覆盖toString()? 听起来有点愚蠢,但我需要帮助我的toString()方法,这是非常irking. 我尝试在网上查找,因为toString是搞砸了,"没有找到K ...

  7. aws中部署防火墙_如何在AWS中设置自动部署

    aws中部署防火墙 by Harry Sauers 哈里·绍尔斯(Harry Sauers) 如何在AWS中设置自动部署 (How to set up automated deployment in ...

  8. MySQL中使用CASE出错,如何在MySQL中正确使用CASE..WHEN

    如何在MySQL中正确使用CASE..WHEN 这里是一个演示查询,注意它非常简单,仅在base_price为0的位置获取,并且仍然select条件3: SELECT CASE course_enro ...

  9. 手写数字识别中多元分类原理_广告行业中那些趣事系列:从理论到实战BERT知识蒸馏...

    导读:本文将介绍在广告行业中自然语言处理和推荐系统实践.本文主要分享从理论到实战知识蒸馏,对知识蒸馏感兴趣的小伙伴可以一起沟通交流. 摘要:本篇主要分享从理论到实战知识蒸馏.首先讲了下为什么要学习知识 ...

最新文章

  1. iOS 注册密码加密 添加了时间戳 遇到的问题...
  2. 用node批量压缩html页面
  3. 第二期阿里巴巴 Java Meetup 来北京了。你来么?
  4. xgboost与gbdt的区别
  5. 修改mysql数据库名方法_安全快速修改Mysql数据库名的5种方法
  6. 编程语言的分类及其优缺点,Python标准输入与输出
  7. js中document.write()使用方法
  8. 随机生成六位不重复数值
  9. 【转】Spark源码分析之-scheduler模块
  10. 中科大 计算机网络1 课程主要内容大概介绍
  11. android 横向铺满,Android开发全程记录(八)——设置ImageView显示的图片铺满全屏(适应魅族等不常见屏幕比例)...
  12. 人人都能看懂的LSTMGRU
  13. 三款新旧 MacBook Pro 怎么选?
  14. 实用win7桌面小工具
  15. Arduino使用火焰传感器
  16. IT是什么行业?就业前景怎么样
  17. 阿里云服务器遇到的问题
  18. 用CCS搭建简单的F28069M工程并控制LED闪烁
  19. 深度学习——图像分类相关模型一览
  20. IMAX6ULL正点原子学习笔记(led汇编驱动)

热门文章

  1. 2023年高企统计年报填写程序
  2. 【认证】【澳大利亚】澳大利亚认证相关,Freeview EPG
  3. jupyter更改路径
  4. 研报精选230217
  5. Allegro加铜皮无法避让走线和孔
  6. 一个对随机过程的理解
  7. 肖博高中数学高考数学重点知识归纳之三角函数与解三角形
  8. 利用公网IP实现外网访问内网http服务器
  9. linux bond 网卡带宽,实战网卡bond
  10. 中国地质大学(武汉)本科毕业论文答辩和论文选题PPT模板