轉自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);
|
好了,今天博客就到這里。技術有限,如有不對歡迎拍磚!