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

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

时间: 2024-12-05 23:10:42

android开发系列之由ContentValues看到的的相关文章

C#程序员学习Android开发系列之SQLite

上篇博客提到过SQLite,它是嵌入式数据库,由于其轻巧但功能强大,被广泛的用于嵌入式设备当中.后来在智能手机.平板流行之后,它作为文件型数据库,几乎成为了智能设备单机数据库的必选,可以随着安卓app打包到apk文件当中. SQLite的官方网站是http://www.sqlite.org/,可以任意下载,上面也有详尽的文档可以参考,这篇博客重点关注SQLite在Android开发中如何使用. 在Android开发中,推荐建立一个类继承自SQLiteOpenHelper来创建数据库操作类,比如:

C#程序员学习Android开发系列之ListView

上篇博客解决了Android客户端通过WebService与服务器端程序进行交互的问题,这篇博客重点关注两个问题,一个是Android应用程序如何与本机文件型数据库SQLite进行交互,另一问题则是如何在ListView中按照我们想要的界面效果进行展示.限于篇幅这篇重点讲ListView,下篇博客重点阐述SQLite. ListView是一个常用的数据显示控件,假设我们要做一个简单的界面,如图所示. 这张图是我直接从Android平板电脑(Android 4.2.2)上面截图下来的,就是一个普通

C#程序员学习Android开发系列之学习路线图

通过前面的3篇博客已经简单的介绍了Android开发的过程并写了一个简单的demo,了解了Android开发的环境以及一些背景知识. 接下来这篇博客不打算继续学习Android开发的细节,先停一下,明确一下接下来的学习目标以及学习路线. 一.对Android开发的基本认识 1.Android原生开发是基于Java语言的,由于我比较擅长C#,所以对Java语言本身不太熟练,需要加强Java语言基础的练习,这一块我会穿插到具体的知识点练习当中,并且在必要的地方给出与C#语言的对比(其实基本上在语法层

快速Android开发系列网络篇之Android-Async-Http

快速Android开发系列网络篇之Android-Async-Http 转:http://www.cnblogs.com/angeldevil/p/3729808.html 先来看一下最基本的用法 AsyncHttpClient client = new AsyncHttpClient(); client.get("http://www.google.com", new AsyncHttpResponseHandler() { @Override public void onSucce

快速Android开发系列网络篇之Retrofit

Retrofit是一个不错的网络请求库,用官方自己的介绍就是: A type-safe REST client for Android and Java 看官网的介绍用起来很省事,不过如果不了解它是怎么实现的也不太敢用,不然出问题了就不知道怎么办了.这几天比较闲就下下来看了一下,了解一下大概实现方法,细节就不追究了.先来看一个官网的例子,详细说明去网官看 简单示例 首先定义请求接口,即程序中都需要什么请求操作 public interface GitHubService { @GET("/use

快速Android开发系列网络篇之Volley

Volley是Google推出的一个网络请求库,已经被放到了Android源码中,地址在这里,先看使用方法 RequestQueue mRequestQueue = Volley.newRequestQueue(context); JsonObjectRequest req = new JsonObjectRequest(URL, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONO

C#程序员学习Android开发系列之Android项目的目录结构

今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目录:存放java源代码的目录,里面建立一个包,包里面有4个java源文件(分别都继承自Activity).由于java要求比较严格,因此要求类名与文件名一致. gen(Generated Java Files)目录:自动产生Java源文件的目录,是由工具自动生成的,一般不需要自己修改.里面主要有一个

C#程序员学习Android开发系列之搭建开发环境

接触Android好久了,记得09年刚在中国大陆有点苗头的时候,我就知道了google有个Android,它是智能机操作系统.后来在Android出1.5版本之后,我第一时间下载了eclipse开发工具.adt以及android sdk,体验了一把android开发,记得当时搭建开发环境相当麻烦.由于android开发是基于Java的,所以除了上述的工具之外,首先需要安装jdk,记得当时流行的是jdk1.5(后来是1.6,现在是1.7,未来是1.8),安装好之后需要设置环境变量. 时隔4年之后,

C#程序员学习Android开发系列之调用WebService

我在学习Android开发过程中遇到的第一个疑问就是Android客户端是怎么跟服务器数据库进行交互的呢?这个问题是我当初初次接触Android时所困扰我的一个很大的问题,直到几年前的一天,我突然想到WebService是否可以呢?让WebService充当服务器端的角色,完成与服务器数据库操作相关的事情,而Android客户端只要按照WebService方法参数的要求去调用就行了.在当时我对这个解决方案的实现还没模糊,我想这个问题也是初学Android的朋友肯定会想到的问题.那么现在就让我们动