Android中AdapterView/Adapter的深度学习
BaseAdapter的深度学习
博主工作了几年,也用了几年的ListView等AdapterView控件,但关于Adapter的一些问题并没有深入下去,终于有时间学习总结下关于BaseAdapter的一些较深入的话题。本文涉及三个话题:Adapter的回收机制和效率提升,getItemViewType()/getViewTypeCount()方法以及notifyDatasetChanged()使用的注意点。
1.Adapter的回收机制和效率提升
Android在绘制Adapter时,系统首先调用getCount()方法,根据它的返回值得到ListView的长度,然后根据这个长度,调用getView()方法逐行绘制。如果ListView的长度超过了屏幕的长度,android只会绘制显示出来的Item,同时,系统会回收走隐藏的Item。
如下图所示,此时系统绘制的只有position:4到positon12这9个Item.若按箭头方法滑动,将回收position12,以及绘制position3.

总的来说,显示出来然后因为拖动而被隐藏的Item才会触发回收。在方法getView(int position, View convertView, ViewGroup parent)中,第二个参数convertView的含义:是代表系统最近回收的View。若整屏能显示9个Item,第一次打开带ListView的控件时,因为并没有回收的View,调用getVIew时,参数convertView的值会为null,否则将不是null,而是最近回收的View的引用.那么合理利用convertView将是提升Adapter效率的关键,否则将会产生大量的new View开销。
1 @Override
2 public View getView(int position, View convertView, ViewGroup parent)
3 {
4 Holder1 holder1 = null;
5 if(null==convertView)
6 {
7 System.out.println("convertView == null" + " position:" + position);
8 holder1=new Holder1();
9 convertView=LayoutInflater.from(mContext).inflate(R.layout.textview, null);
10 holder1.textView=(TextView)convertView.findViewById(R.id.textview);
11 convertView.setTag(holder1);
12 }
13 else
14 {
15 holder1=(Holder1)convertView.getTag();
16 System.out.println("重用:" + holder1.textView.getText());
17 }
18 holder1.textView.setText("position: "+position);
19 return convertView;
20 }
21
22 class Holder1
23 {
24 public TextView textView;
25 }
说明一下上图中的例子,按箭头方法拖动,接下来将显示position=4的Item,系统调用getView方法时,第二个参数convertView的值将是position=12的View的引用(最近回收的一个Item的View).[读者可在convertView中用一个TextView记录下每个View的position值,就可发现这个规律]
精致的逻辑说明:系统绘制Item的View和回收Item的View时有个规则:该Item只要显示出一点点就触发绘制,但必须等该Item完全隐藏之后才触发回收。试验上例时若结果对不上请注意这条说明。
2.getItemViewType()/getViewTypeCount()方法
若果Item的View都是同一个模板则用不到这俩方法,但很多情况下我们的AdapterView中可能会用到2个或以上的不同的模板,那这些不同的模板如何复用,那就是这俩方法的作用。
看下官方对convertView的解释:The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)). 意思大概就是: 在有些AdapterView的使用中,比如微博中 有的item中包含图片 有的item包含视频 那么必然的 我们需要用到2种item的布局方式此时如果只是单纯判断“null==convertView”,会造成回收的view不符合你当前需要的布局 而类似转换失败出错退出。
代码示例:
1 @Override
2 public View getView(int position, View convertView, ViewGroup parent)
3 {
4 Holder1 holder1 = null;
5 Holder2 holder2 = null;
6 int type = getItemViewType(position);
7 if(null==convertView)
8 {
9 switch (type) {
10 case TYPE_1:
11 System.out.println("convertView == null" + " position:" + position);
12 holder1=new Holder1();
13 convertView=LayoutInflater.from(mContext).inflate(R.layout.textview, null);
14 holder1.textView=(TextView)convertView.findViewById(R.id.textview);
15 convertView.setTag(holder1);
16 break;
17 case TYPE_2:
18 System.out.println("convertView == null" + " position:" + position);
19 holder2=new Holder2();
20 convertView=LayoutInflater.from(mContext).inflate(R.layout.imageview, null);
21 holder2.imageView=(ImageView)convertView.findViewById(R.id.imageview);
22 convertView.setTag(holder2);
23 break;
24 default:
25 break;
26 }
27 }
28 else
29 {
30 switch (type) {
31 case TYPE_1:
32 holder1=(Holder1)convertView.getTag();
33 System.out.println("重用:" + holder1.textView.getText());
34 break;
35 case TYPE_2:
36 holder2=(Holder2)convertView.getTag();
37 break;
38 default:
39 break;
40 }
41 }
42 switch (type)
43 {
44 case TYPE_1:
45 holder1.textView.setText("position: "+position);
46 break;
47 case TYPE_2:
48 holder2.imageView.setBackgroundColor(colors[position%6]);
49 break;
50 default:
51 break;
52 }
53 return convertView;
54 }
55
56 class Holder1
57 {
58 public TextView textView;
59 }
60
61 class Holder2
62 {
63 public ImageView imageView;
64 }
65
66 @Override
67 public int getItemViewType(int position)
68 {
69 if(position < 2)
70 return TYPE_1;
71 else if(position%2==0)
72 return TYPE_1;
73 else
74 return TYPE_1;
75 }
76
77 @Override
78 public int getViewTypeCount()
79 {
80 return 2;
81 }

这个例子中有两点需要说明:
1.在getItemTypeView()方法中的返回值不是随便设置的,在SDK中有句话“Note: Integers must be in the range 0 to getViewTypeCount() - 1”。也就是说:返回值得返回必须是0 - (getViewTypeCount()-1)范围内。
2.关于setTag()和getTag()的理解:初学者对这两个方法可能不能很好的理解,调用setTag("")方法时,可以理解为为View设置了一个标识,然后通过getTag()来获取标识,或者理解为View作为一个容器除了显示一些字符串,图片之外,还可以通过setTag("")方法往其中存放一些数据,然后通过通过getTag()来获取数据。
说明:我自己在学习这个知识点的过程中,产生了一个奇怪问题:我不用继承父类的这两个方法,自定义方法也可以完成这个功能,想通了之后发现时钻了牛角尖,就不讨论这个问题,若读者也产生了这个问题,可留言交流。
3.notifyDatasetChanged()使用
首先看SDK中的说明:Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself. 这句话也好理解。我们在使用该方法过程中,有时候会发现不生效。
1 //我们通常通过构造器将list赋给自定义的Adapter
2 ArrayList<String> list = new ArrayList<String>();
3 MyAdapter adapter = new MyAdapter(context,list);
4
5 list = query(...);
6 adapter.notifyDataSetChanged();
这时notifyDataSetChanged()是不会生效的,应该改为:
1 list.clear();
2 list.addAll(query(...));
3 adapter.notifyDataSetChanged();
这不是android的问题,而是Java特性相关的问题。Java语言的变量中存的是引用。使用"list=query(...);"时,效果是改变了list的引用,而MyAdapter中使用的还是原来的引用,所以notifyDataSetChanged()时不能生效。正确的做法是通过方法来操作对象本身,而不是改变其引用。
Demo百度云链接:http://pan.baidu.com/s/1dDAAVhZ (找不到更好的链接方式,如果有更好地方式请留言告诉我。)
Author:Andy Zhai
2014-01-01 19:20:52
Android中AdapterView/Adapter的深度学习的更多相关文章
- Android中的Adapter 详解
http://blog.csdn.net/tianfeng701/article/details/7557819 (一) Adapter介绍 Android是完全遵循MVC模式设计的框架,Activi ...
- Android中各种Adapter的使用方法
1.概念 Adapter是连接后端数据和前端显示的适配器接口.是数据和UI(View)之间一个重要的纽带.在常见的View(ListView,GridView)等地方都须要用到Adapter.例如以下 ...
- Android学习四、Android中的Adapter
一.Adapter的介绍 An Adapter object acts as a bridge between an AdapterView and the underlying data for t ...
- Android中的Adapter总结
一.Adapter的介绍 An Adapter object acts as a bridge between an AdapterView and the underlying data for t ...
- 使用具体解释及源代码解析Android中的Adapter、BaseAdapter、ArrayAdapter、SimpleAdapter和SimpleCursorAdapter
Adapter相当于一个数据源,能够给AdapterView提供数据.并依据数据创建相应的UI.能够通过调用AdapterView的setAdapter方法使得AdapterView将Adapter作 ...
- Android笔记(二十一) Android中的Adapter
Android中有一些View是包含多个元素的,例如ListView,GridView等,为了给View的每一个元素都设置数据,就需要Adapter了. 常用的Adapter包括ArrayAdapte ...
- android中与Adapter相关的控件----ListView
ListView讲解: 一.ListView这个控件是一个使用非常广泛的控件,值得深入的学习和研究.基本使用已经在Adapter中使用过了 二.常用的属性和方法 footerDividersEnabl ...
- android中与Adapter相关的控件----ExpandableListView
ExpandableListView(可折叠的列表) 一.ExpandableListView(可折叠的列表)和ListView有很多地方差不多的,使用也差不多,只是他们使用适配器不一样的,Expan ...
- android中与Adapter相关的控件----GridView
GridView(网格视图)讲解 一.GridView(网格视图)这个是控件也是比较多,和listView的很多地方都是一样的,但是GridView可以显示多列,而listView只能显示一列,个人觉 ...
随机推荐
- php Pthread 线程 互斥锁
在进行并发操作时,会导致共享数据的完整性的问题,要加入锁,在任意时刻只有一个线程访问该对象在PHP中定义专门用于线程同步控制的mutex的函数, pthreads v3 中已经将 Mutex 类移除. ...
- javaweb开发.常用的第三方包
序号 开发包名称 描述 1 dom4j-1.6.1.jar dom4j用于操作XML文件 2 jaxen-1.1-beta-6.jar 用于解析XPath表达式 3 commons-beanuti ...
- Eclipse中 *.properties 文件编码设置
Eclipse 中的默认编码格式为 ISO-8895-1,在此编码下中文的会显示如下的效果 解决方法 Windows --> Preference --> General Types -- ...
- 牛客练习赛42 C 反着计算贡献
https://ac.nowcoder.com/acm/contest/393/C 题意 给你一个矩阵, 每次从每行挑选一个数,组成一个排列,排列的和为不重复数字之和,求所有排列的和(n,m<= ...
- str相关操作
大小写转换:*——记住 * upper() 全大写 title() 首字母大写(只要是不属于英文字母的都是分隔符) 切来切去: center(10,'*') 强行用*在原字符串左右两端拼接,拼接成十个 ...
- SSM_CRUD新手练习(9)显示分页数据
我们已经做好了用来显示数据的分页模板,现在只需要将我们从后台取出的数据填充好,显示出来. 我们使用<c:forEach>标签循环取出数据,所以需要先导入JSTL标签库 <%@ tag ...
- 查看服务器tcp连接及服务器并发
一.查看哪些IP连接本机netstat -an二.查看TCP连接数1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数 ...
- oracle utl_http 访问https类型
https://oracle-base.com/articles/misc/utl_http-and-ssl http://blog.whitehorses.nl/2010/05/27/access- ...
- Java RMI 使用例子
1.创建协议接口(UserService) /** * */ package com.junge.demo.rmi.protocol.service; import java.io.Serializa ...
- 技术文档生成工具:appledoc
做项目一般都会要求写技术文档,特别是提供SDK或者基础组件的.如果手写这类技术文档的话,工作量比编写代码也少不了多少.比如 Java 语言本身就自带 javadoc 命令,可以从源码中抽取文档.本篇我 ...