android开发系列之由ContentValues看到的
这本篇博客里面我想重点来分析一下ContentValues的源码以及它里面涉及到的继承接口Parcelabel,还有HashMap的源码。
相信使用过android里面数据库操作的朋友对于ContentValues一定不会感到陌生吧,它其实很像一个字典对象,可以用来存储键值对。比如代码如下:
ContentValues contentValues=new ContentValues();
contentValues.put("name","xiao");
contentValues.put("age",20);
contentValues.put("isStudent",true);
你会发现ContentValues里面可以用来put各种类型的数据,它是怎样拥有这种神奇的功能的呢?下面让我们来看看它的源码。首先,是ContentValues类的定义:
public final class ContentValues implements Parcelable {
}
我们可以看到它实现了Parcelabel接口,这个接口主要是用来实现数据安装、传输相关操作的。说到这里,让我们也来看看Parcelabel接口里面到底定义了哪些方法,源码如下:
public interface Parcelable { public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001; public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001; public int describeContents(); public void writeToParcel(Parcel dest, int flags); public interface Creator<T> { public T createFromParcel(Parcel source); public T[] newArray(int size);
} public interface ClassLoaderCreator<T> extends Creator<T> { public T createFromParcel(Parcel source, ClassLoader loader);
}
}
我们可以看到里面有个writeToParcel方法是用来传输数据的,至于它是怎么用来包装数据的,就要看看具体实现Parcelabel接口类的实现了。
好了说回我们所要讨论的重点对象ContentValues,首先来看看ContentValues里面包括的构造函数,源码如下所示:
private HashMap<String, Object> mValues; public ContentValues() {
// Choosing a default size of 8 based on analysis of typical
// consumption by applications.
mValues = new HashMap<String, Object>(8);
} /**
* Creates an empty set of values using the given initial size
*
* @param size the initial size of the set of values
*/
public ContentValues(int size) {
mValues = new HashMap<String, Object>(size, 1.0f);
} /**
* Creates a set of values copied from the given set
*
* @param from the values to copy
*/
public ContentValues(ContentValues from) {
mValues = new HashMap<String, Object>(from.mValues);
} /**
* Creates a set of values copied from the given HashMap. This is used
* by the Parcel unmarshalling code.
*
* @param values the values to start with
* {@hide}
*/
private ContentValues(HashMap<String, Object> values) {
mValues = values;
}
相信大家从注释里面就能够看看,ContentValues的构造主要是根据代码里面传入的具体参数来构造对应的HashMap对象,然后里面的各种put操作、get操作、remove操作都是针对HashMap进行的,其中put类型的方法源码如下:
public void put(String key, String value) {
mValues.put(key, value);
} public void putAll(ContentValues other) {
mValues.putAll(other.mValues);
} public void put(String key, Byte value) {
mValues.put(key, value);
} public void put(String key, Short value) {
mValues.put(key, value);
} public void put(String key, Integer value) {
mValues.put(key, value);
} public void put(String key, Long value) {
mValues.put(key, value);
} public void put(String key, Float value) {
mValues.put(key, value);
} public void put(String key, Double value) {
mValues.put(key, value);
} public void put(String key, Boolean value) {
mValues.put(key, value);
} public void put(String key, byte[] value) {
mValues.put(key, value);
} public void putNull(String key) {
mValues.put(key, null);
}
通过上面的方法,我们就能够明白为什么ContentValues能够put各种类型的数值了吧,接下来让我们来看看get方法,源码如下:
public Object get(String key) {
return mValues.get(key);
} public String getAsString(String key) {
Object value = mValues.get(key);
return value != null ? value.toString() : null;
} public Long getAsLong(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).longValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Long.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Long value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Long: " + value, e);
return null;
}
}
} public Integer getAsInteger(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).intValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Integer.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Integer value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Integer: " + value, e);
return null;
}
}
} public Short getAsShort(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).shortValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Short.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Short value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Short: " + value, e);
return null;
}
}
} public Byte getAsByte(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).byteValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Byte.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Byte value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Byte: " + value, e);
return null;
}
}
} public Double getAsDouble(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).doubleValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Double.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Double value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Double: " + value, e);
return null;
}
}
} public Float getAsFloat(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).floatValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Float.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Float value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Float: " + value, e);
return null;
}
}
} public Boolean getAsBoolean(String key) {
Object value = mValues.get(key);
try {
return (Boolean) value;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
return Boolean.valueOf(value.toString());
} else if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Boolean: " + value, e);
return null;
}
}
} public byte[] getAsByteArray(String key) {
Object value = mValues.get(key);
if (value instanceof byte[]) {
return (byte[]) value;
} else {
return null;
}
}
通过上面的代码我们也能很直观的看到,不同的get方法通过调用不同类型的((Number)value).intValue方法强转一次获取,如果拿不到的话就返回null。
既然ContentValues是基于HashMap去实现操作的,那么我们有必要来看看HashMap到底是怎么回事?首先是HashMap类定义,源码如下所示:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
}
通过上面的代码,我们可以看到HashMap是基于泛型去构建的,同时实现了克隆和序列化接口。这就意味着在一定程度上面,我们可以实例化任何类型的HashMap,并且使它具有克隆、序列化的功能,请看如下代码:
HashMap<Integer,Object> hashOne=new HashMap<>();
HashMap<String,Object> hashTwo=new HashMap<>();
HashMap<Boolean,Object> hashThree=new HashMap<>();
HashMap<Float,Object> hashFour=new HashMap<>();
只不过我们通常在项目里面一般都习惯使用String类型的key。好了,让我们继续往下看,首先最应该说的就是HashMapEntry内部静态类了,源码如下:
static class HashMapEntry<K, V> implements Entry<K, V> {
final K key;
V value;
final int hash;
HashMapEntry<K, V> next; HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
} public final K getKey() {
return key;
} public final V getValue() {
return value;
} public final V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
} @Override public final boolean equals(Object o) {
if (!(o instanceof Entry)) {
return false;
}
Entry<?, ?> e = (Entry<?, ?>) o;
return Objects.equal(e.getKey(), key)
&& Objects.equal(e.getValue(), value);
} @Override public final int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
} @Override public final String toString() {
return key + "=" + value;
}
}
HashMapEntry类实现了Entry接口,而Entry接口又是Map接口里面的一个内部接口。通过实现Entry接口,从而使HashMap具有了getKey/getValue/setValue等相关功能。同时我们可以看到HashMap里面好多功能的实现都是针对HashMapEntry展开的。另外HashMap还有个比较重要的概念就是Set接口,让我们来看看里面final类型的私有内部类EntrySet,源码如下:
private final class EntrySet extends AbstractSet<Entry<K, V>> {
public Iterator<Entry<K, V>> iterator() {
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Entry))
return false;
Entry<?, ?> e = (Entry<?, ?>) o;
return containsMapping(e.getKey(), e.getValue());
}
public boolean remove(Object o) {
if (!(o instanceof Entry))
return false;
Entry<?, ?> e = (Entry<?, ?>)o;
return removeMapping(e.getKey(), e.getValue());
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
HashMap.this.clear();
}
}
正如其名一样,Set接口里面主要是提供HashMap的设置相关操作。让我们来看看Set接口里面的源码,如下:
public boolean add(E object); public boolean addAll(Collection<? extends E> collection); public void clear(); public boolean contains(Object object); public boolean containsAll(Collection<?> collection); public boolean equals(Object object); public int hashCode(); public boolean isEmpty(); public Iterator<E> iterator(); public boolean remove(Object object); public boolean removeAll(Collection<?> collection); public boolean retainAll(Collection<?> collection); public int size(); public Object[] toArray(); public <T> T[] toArray(T[] array);
好了,今天博客就到这里。技术有限,如有不对欢迎拍砖!
android开发系列之由ContentValues看到的的更多相关文章
- Android 开发系列教程之(一)Android基础知识
什么是Android Android一词最早是出现在法国作家维里耶德利尔·亚当1986年发表的<未来夏娃>这部科幻小说中,作者利尔·亚当将外表像人类的机器起名为Android,这就是And ...
- Android开发系列之SQLite
上篇博客提到过SQLite,它是嵌入式数据库,由于其轻巧但功能强大,被广泛的用于嵌入式设备当中.后来在智能手机.平板流行之后,它作为文件型数据库,几乎成为了智能设备单机数据库的必选,可以随着安卓app ...
- [Android开发系列]IT博客应用
1.关于坑 好吧,在此之前先来说一下,之前开的坑,恩,确实是坑,前面开的两个android开发教程的坑,对不起,实在是没什么动力了,不过源码都有的,大家可以参照github这个应用 https://g ...
- Android开发系列之按钮事件的4种写法
经过前两篇blog的铺垫,我们今天热身一下,做个简单的例子. 目录结构还是引用上篇blog的截图. 具体实现代码: public class MainActivity extends Activity ...
- Android开发系列之Android项目的目录结构
今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...
- Android开发系列之学习路线图
通过前面的3篇博客已经简单的介绍了Android开发的过程并写了一个简单的demo,了解了Android开发的环境以及一些背景知识. 接下来这篇博客不打算继续学习Android开发的细节,先停一下,明 ...
- Android开发系列之搭建开发环境
接触Android好久了,记得09年刚在中国大陆有点苗头的时候,我就知道了google有个Android,它是智能机操作系统.后来在Android出1.5版本之后,我第一时间下载了eclipse开发工 ...
- VS2015下的Android开发系列01——开发环境配置及注意事项
概述 VS自2015把Xamarin集成进去后搞Android开发就爽了,不过这安装VS2015完成的时候却是长了不知道多少.废话少说进正题,VS2015安装时注意把Android相关的组件勾选安装, ...
- Android开发系列----sdk下载 环境准备
今天开始准备Android开发环境,FQ下载Android Studio,官网下载地址 https://developer.android.com/studio/install.html (突然发现我 ...
随机推荐
- CSS用border绘制三角形
使用border绘制三角形的思路,就是border尺寸设置一个较大的值,元素自身的宽高设置为0,全部由边线占据,这样每边就会显示为四分之一块的三角形.这样不借助图片,可以直接绘制出三角形了. 一个栗子 ...
- ASP.NET Session丢失的情况
正常操作情况下会有ASP.NET Session丢失的情况出现.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定成60分钟,不会这么快就超时的. 现在我就把原 ...
- 纯servlet返回xml数据
... void doget..... response.setContentType("application/xml");//设置格式 PrintWriter out = r ...
- 去HTML代码
Code: public static string NoHTML(string Htmlstring) { //删除脚本 Htmlstring = Regex.Replace(Htmlstring, ...
- .NET如何从配置文件中获取连接字符串
一.设置配置文件 <configuration> <!--在configuration下创建一个connectionStrings--> <connectionStrin ...
- 音乐社交APP源码 V1.1
1.关于音乐曲库,对接的是百度音乐,会自动随搜索链接百度曲库2.便捷聊天,采用xmpp基本架构.3.加入和整理了群聊天.4.分布式聊天,喜欢该专辑直接进入聊天,喜欢该音乐的进入聊天.5.采用兴趣社交和 ...
- 常用的MyEclipse快捷键
在调试程序的时候,我们经常需要注释一些代码,在用Myeclipse编程时,就可以用 Ctrl+/ 为选中的一段代码加上以 // 打头的注释:当需要恢复代码功能的时候,又可以用Ctrl+/ 去掉注释.这 ...
- jquery中选择ID以什么字符开头的匹配主要用于多个上传控件的时候,id无法使用,而且class不起作用的时候
$("[id^=remark]")选择ID以remark开头的所有数据进行匹配
- jquery导航二级栏目下拉
<div class="Nav_L L"> <ul> <li><a href="" title="" ...
- PHP伪造referer突破防盗链
php伪造referer实例代码,主要用于一些突破防盗链. 可以从这个例子中发展出很多的应用.比如隐藏真实的URL地址……嘿嘿,具体的就自己分析去吧 这里新建一个文件file.php.后面的参数就是需 ...