Android SimpleAdapter源码详解
一直没认真看过android的源码,也不太敢看,稀里糊涂也敲了一年的代码,现在想好好学习了,就把常用的源码都看了一下,小伙伴们来涨姿势吧,有错误的地方,直接指出,我脸厚不怕丢人。来吧。
刚开始学android的时候我经常使用SimpleAdapter,但是后来经常用到的对象实体,SimpleAdapter也就不符合要求了,一直自己继承BaseAdapter,但是有的地方用SimpleAdapter还是比较方便的,一句话就搞定了,也不用写Adapter,所以来悄悄源码吧。
SimpleAdapter的初始化:
SimpleAdapter sAdapter=new SimpleAdapter(this, mList, R.layout.activity_main,new String[]{"name","pwd"},new int[]{R.id.tv_name,R.id.tv_pwd});
下面是android的源码,加了详细的注释,不用再多说:
public class SimpleAdapter extends BaseAdapter implements Filterable {
private int[] mTo; // 指向布局里面控件的id 比如:R.id.btn
private String[] mFrom; // 数据来源,来自Map里面的key
private ViewBinder mViewBinder;// 接口类型,里面有个setViewValue方法,用于出现特殊类型控件比如:drawable的时候在外部初始化接口,实现具体方法 private List<? extends Map<String, ?>> mData;// 用List打包的Map数据源 private int mResource;// 布局
private int mDropDownResource;// 不知道干嘛用的,但是估计也是留给外部调用的
private LayoutInflater mInflater;// 这个大家都知道,LayoutInflater用来载入界面 private SimpleFilter mFilter;// 过滤器,一般用不到
private ArrayList<Map<String, ?>> mUnfilteredData; // SimpleAdapter初始化,将传进了的参数都赋给本地的对应变量
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to) {
mData = data;
mResource = mDropDownResource = resource;
mFrom = from;
mTo = to;
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
} /*
* ListView 针对每个item,要求 adapter “返回一个视图” (getView),
* 也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,
* 然后根据这个长度,调用getView()一行一行的绘制ListView的每一项。如果你的getCount()返回值是0的话,
* 列表一行都不会显示,如果返回1,就只显示一行。返回几则显示几行。如果我们有几千几万甚至更多的item要显示怎么办?
* 为每个Item创建一个新的View?不可能!!!实际上Android早已经缓存了这些视图,大家可以看下下面这个截图来理解下,
* 这个图是解释ListView工作原理的最经典的图了大家可以收藏下,不懂的时候拿来看看,加深理解,
* 其实Android中有个叫做Recycler的构件
*/
public int getCount() {
return mData.size();
} public Object getItem(int position) {
return mData.get(position);
} public long getItemId(int position) {
return position;
} public View getView(int position, View convertView, ViewGroup parent) {
// 调用createViewFromResource来优化内存
return createViewFromResource(position, convertView, parent, mResource);
} /*
* ListView的机制在这里再说一下,当第一个数据来getView的时候convertView肯定是null,
* 那么就用mInflater.inflate(resource, parent,
* false)给它初始化一个View,但是当一屏滑到底了,第一个item,滑出了屏幕,那么它将
* 从底部出来,那时候convertView就不为null,这个方法的好处就是当convertView不为null
* 的时候不用加载布局,直接使用convertView, 节省了一步,这也是所说的优化ListView的第一个步骤。
*/
private View createViewFromResource(int position, View convertView,
ViewGroup parent, int resource) {
View v;
if (convertView == null) {
v = mInflater.inflate(resource, parent, false);
} else {
v = convertView;
}
// 这个方法是核心
bindView(position, v); return v;
} public void setDropDownViewResource(int resource) {
this.mDropDownResource = resource;
} @Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return createViewFromResource(position, convertView, parent,
mDropDownResource);
} // 这个方法的主要功能就是按照 to数组里面控件的顺序挨个赋值,比如new int[]{R.id.tv_name,R.id.tv_pwd}。
private void bindView(int position, View view) {
final Map dataSet = mData.get(position);// 找到对应的position位置的map数据
// 如果没找到跳出
if (dataSet == null) {
return;
}
/*
* 将外部实现的ViewBinder,赋值给本地,SimpleAdapter能够实现:
* checkBox,CheckedTextView,TextView
* ,ImageView,数据类型也就是Boolean,Integer,Stirng, 所以特殊数据类型的时候才用到ViewBinder
* ,如果没用到就不需要外部实现ViewBinder接口和里面的方法
*/
final ViewBinder binder = mViewBinder;
final String[] from = mFrom;
final int[] to = mTo;
final int count = to.length;
//view.findViewById(to[i]),循环找控件
for (int i = 0; i < count; i++) {
final View v = view.findViewById(to[i]);
//如果v不为空的话,找到对应的数据,Object类型的data转换为String,因为boolean在map里面纯的也是true或者false
if (v != null) {
final Object data = dataSet.get(from[i]);
String text = data == null ? "" : data.toString();
if (text == null) {
text = "";
}
//标志变量bound,判断外部有没有实现ViewBinder,如果实现了,就执行binder.setViewValue(v, data, text),如果符合特殊条件,就返回true
boolean bound = false;
if (binder != null) {
bound = binder.setViewValue(v, data, text);
}
//如果满足if (!bound)那么bound就还是false,说明是普通数据
if (!bound) {
//查看v是不是Checkable的实例化类型,满足的情况可能是CheckBox,CheckedTextView
if (v instanceof Checkable) {
//如果数据类型是boolean,那么就是CheckBox
if (data instanceof Boolean) {
((Checkable) v).setChecked((Boolean) data);
//如果不是CheckBox,那么判断是不是继承TextView的CheckedTextView,是的话赋值,不是就抛出异常
} else if (v instanceof TextView) {
setViewText((TextView) v, text);
} else {
throw new IllegalStateException(v.getClass()
.getName()
+ " should be bound to a Boolean, not a "
+ (data == null ? "<unknown type>"
: data.getClass()));
}
//如果不是Checkable的实例化类型,判断是不是TextView的实例化类型
} else if (v instanceof TextView) {
setViewText((TextView) v, text);
//都不是以上情况,就判断一下是不是ImageView的实例化类型
} else if (v instanceof ImageView) {
//这里只满足数据类型为int也就是R.drawable.ic,和String类型的url,如果想实现直接用drawbale,就要实现ViewBinder
if (data instanceof Integer) {
setViewImage((ImageView) v, (Integer) data);
} else {
setViewImage((ImageView) v, text);
}
} else {
throw new IllegalStateException(
v.getClass().getName()
+ " is not a "
+ " view that can be bounds by this SimpleAdapter");
}
}
}
}
} public ViewBinder getViewBinder() {
return mViewBinder;
} public void setViewBinder(ViewBinder viewBinder) {
mViewBinder = viewBinder;
} public void setViewImage(ImageView v, int value) {
v.setImageResource(value);
} public void setViewImage(ImageView v, String value) {
try {
v.setImageResource(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
v.setImageURI(Uri.parse(value));
}
} public void setViewText(TextView v, String text) {
v.setText(text);
} public Filter getFilter() {
if (mFilter == null) {
mFilter = new SimpleFilter();
}
return mFilter;
} public static interface ViewBinder {
boolean setViewValue(View view, Object data, String textRepresentation);
}
//这个不知道干嘛用的,也没用过,好像是过滤数据的
private class SimpleFilter extends Filter { @Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults(); if (mUnfilteredData == null) {
mUnfilteredData = new ArrayList<Map<String, ?>>(mData);
} if (prefix == null || prefix.length() == 0) {
ArrayList<Map<String, ?>> list = mUnfilteredData;
results.values = list;
results.count = list.size();
} else {
String prefixString = prefix.toString().toLowerCase(); ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
int count = unfilteredValues.size(); ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(
count); for (int i = 0; i < count; i++) {
Map<String, ?> h = unfilteredValues.get(i);
if (h != null) { int len = mTo.length; for (int j = 0; j < len; j++) {
String str = (String) h.get(mFrom[j]); String[] words = str.split(" ");
int wordCount = words.length; for (int k = 0; k < wordCount; k++) {
String word = words[k]; if (word.toLowerCase().startsWith(prefixString)) {
newValues.add(h);
break;
}
}
}
}
} results.values = newValues;
results.count = newValues.size();
} return results;
} @Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// noinspection unchecked
mData = (List<Map<String, ?>>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}
最近在公司涨了很多姿势,大部分是Java的继承,接口,多态,抽象这些学过但是理解很肤浅的东西,以前自己写软件没什么规范,也没怎么去抽象,所以代码很不上档次,老鸟看到我的代码就笑话我,现在我准备好好学一下,希望自己有一天也能写出很正规的代码。
Android SimpleAdapter源码详解的更多相关文章
- Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解
Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解 今天主要理一下StreamingContext的启动过程,其中最为重要的就是Jo ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- 条件随机场之CRF++源码详解-预测
这篇文章主要讲解CRF++实现预测的过程,预测的算法以及代码实现相对来说比较简单,所以这篇文章理解起来也会比上一篇条件随机场训练的内容要容易. 预测 上一篇条件随机场训练的源码详解中,有一个地方并没有 ...
- [转]Linux内核源码详解--iostat
Linux内核源码详解——命令篇之iostat 转自:http://www.cnblogs.com/york-hust/p/4846497.html 本文主要分析了Linux的iostat命令的源码, ...
- saltstack源码详解一
目录 初识源码流程 入口 1.grains.items 2.pillar.items 2/3: 是否可以用python脚本实现 总结pillar源码分析: @(python之路)[saltstack源 ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- udhcp源码详解(五) 之DHCP包--options字段
中间有很长一段时间没有更新udhcp源码详解的博客,主要是源码里的函数太多,不知道要不要一个一个讲下去,要知道讲DHCP的实现理论的话一篇博文也就可以大致的讲完,但实现的源码却要关心很多的问题,比如说 ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
- 源码详解系列(六) ------ 全面讲解druid的使用和源码
简介 druid是用于创建和管理连接,利用"池"的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制.连接可靠性测试.连接泄露控制.缓存语句等功能,另外,druid还扩展 ...
随机推荐
- 一个C语言宏展开问题
转自一个C语言宏展开问题 一个令人比较迷惑的问题,学C语言好多年,今天终于搞明白,记之. ------------------------------------------------------- ...
- OpenStack项目列表
这个也是必须要熟悉的哟. ~~~~~~~~~~ OpenStack是一个美国国家航空航天局和Rackspace合作研发的,以Apache许可证授权,并且是一个自由软件和开放源代码项目.OpenStac ...
- HTML textarea输入框限制长度 (引)
引自:http://aqingsao.iteye.com/blog/398897 textarea在Web开发中经常用到,但是它本身不支持maxlength,可以通过下面的js实现: function ...
- ASP.NET MVC 入门介绍 (上)
MVC模式 MVC模式是一种软件架构模式.它把软件系统分为三个部分:模型(Model),视图(View)和控制器(Controller).MVC模式最早由Trygve Reenskaug在1974年提 ...
- easyui源码翻译1.32--TreeGrid(树形表格)
前言 扩展自$.fn.datagrid.defaults.使用$.fn.treegrid.defaults重写默认值对象.下载该插件翻译源码 树形表格用于显示分层数据表格.它是基于数据表格.组合树控件 ...
- QT使用UAC(经过验证)
网上有很多manifest的版本,mingw与vs系列也有不同的解决方案,不管那么多,我是使用这篇文章解决这个问题的: So it turns out that I had another bug t ...
- 134. Gas Station
题目: There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. ...
- Linux 信号signal处理机制
信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念.Linux对信号机制的大致实现方法.如何使用信号,以及有关信号的几个系统调用. 信号机制是进程之间相互传递消息的一种方法,信号全 ...
- IBM Rational-完整的软件工程解决方案工具集
IBM,即国际商业机器公司,1911年创立于美国,是全球最大的信息技术和业务解决方案公司,其业务遍及全球170多个国家和地区.IBM软件分为五个部分,其中Rational系列是专门针对软件工程的软件工 ...
- Java实现人民币大写精讲
想要实现人民币大写,在发票等场景中使用?? 1234.56显示为:壹仟贰佰叁拾肆元伍角陆分,那就往下看看吧! 本程序可以实现 0 到 9999 9999 9999.994 以内的人民币大写转换,精确到 ...