zoukankan      html  css  js  c++  java
  • 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);
    

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

  • 相关阅读:
    EF数据迁移完整步骤
    ajax跨域最全解决方案
    WPF控件与WPF窗体
    WPF模板是把控件MVC模式化
    对象与类型
    Java加权负载均衡策略
    db2列式存储
    linux离线安装mongodb及java调用
    python合并目录下excel数据
    python多线程迁移db2数仓9T数据
  • 原文地址:https://www.cnblogs.com/xiaocai20091687/p/xiaocai-android-contentvalues.html
Copyright © 2011-2022 走看看