转自https://www.cnblogs.com/xiaocai20091687/p/xiaocai-android-contentvalues.html
这本篇博客里面我想重点来分析一下ContentValues的源码以及它里面涉及到的继承接口Parcelabel,还有HashMap的源码。
相信使用过android里面数据库操作的朋友对于ContentValues一定不会感到陌生吧,它其实很像一个字典对象,可以用来存储键值对。比如代码如下:
1
2
3
4
|
ContentValues contentValues=
new
ContentValues();
contentValues.put(
"name"
,
"xiao"
);
contentValues.put(
"age"
,
20
);
contentValues.put(
"isStudent"
,
true
);
|
你会发现ContentValues里面可以用来put各种类型的数据,它是怎样拥有这种神奇的功能的呢?下面让我们来看看它的源码。首先,是ContentValues类的定义:
1
2
|
public
final
class
ContentValues
implements
Parcelable {
}
|
我们可以看到它实现了Parcelabel接口,这个接口主要是用来实现数据安装、传输相关操作的。说到这里,让我们也来看看Parcelabel接口里面到底定义了哪些方法,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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里面包括的构造函数,源码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
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类型的方法源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
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方法,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
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类定义,源码如下所示:
1
2
|
public
class
HashMap<K, V>
extends
AbstractMap<K, V>
implements
Cloneable, Serializable{
}
|
通过上面的代码,我们可以看到HashMap是基于泛型去构建的,同时实现了克隆和序列化接口。这就意味着在一定程度上面,我们可以实例化任何类型的HashMap,并且使它具有克隆、序列化的功能,请看如下代码:
1
2
3
4
|
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内部静态类了,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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接口里面的源码,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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);
|
好了,今天博客就到这里。技术有限,如有不对欢迎拍砖!