ContentValues介绍及使用

转自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);

       好了,今天博客就到这里。技术有限,如有不对欢迎拍砖!

原文地址:https://www.cnblogs.com/antble/p/7978654.html