Content Provider

在数据处理中,Android通常使用Content Provider的方式。Content Provider使用Uri实例作为句柄的数据封装的,很方便地访问地进行数据的增、删、改、查的操作。Android并不提供所有应用共享的数据存储,采用content Provider,提供简单便捷的接口来保持和获取数据,也可以实现跨应用的数据访问。简单地说,Android通过content Provider从数据的封装中获取信息。

Content provider使用Uri的方式来定位信息。以“content://” 开头来表明这是一个content URI。例如“content://contstans/5”,其中“content://constans”称为base URI,相当于数据的namespace,它的结构可以更为复杂,可以有多层结构。例子中的“5”,则是具体实例的标识。

一般来讲,Android的数据存储有4种方式:

1、 Preferences,参见Preference的使用,通常都是键值对(name-value pair)。
2、文件:在手机设备或者外设上存储,缺省的只能由创建的应用访问。
3、数据库(RDBMS):SQLite方式,参见SQLite的使用,由创建的应用访问。
4、网络:Android提供API远程在服务器上存储数据。

如果我们需要在应用中共享,采用Content Provider。无论数据具体的存储方式,Content Provider提供了一个统一的接口。数据将采用类表格的方式提供,有行有列,列表示不同属性的数据,例如电话号码、电邮地址等。每个记录(每行)都有一个唯一的_ID字段来标识。在以后具体的代码中看更直观看出。

原生providers

Android提供一些原生的content provider,来往问系统中的视频、图像和联系人信息等等。例如联系人的URI为“content://com.android.contacts /contacts”,原生的providers一般都有定义,例如联系人为 ContactsContract.Contacts.CONTENT_URI。由于系统不同版本可能会存在差异,我们应尽可能使用系统的定义。

在android.provider的包中,可以查看原生的provider,例如有AlarmClock、Browser、CalendarContract、CallLog、 ContactsContract(包括有Contacts,Groups,PhoneLookup等)、MediaStore(Audio 『Albums、Artists、Genres、Playlists』、Files、Images、Video)和Setting。

通过Content Providers读取信息

我们利用原生provider联系人来看看如何来读取信息,联系人的数据结构比较复杂,后面会详细介绍,这里我们将尽可能简化,先对Content Provider有个直观的认识。核心是通过managedQuery( )来获取Cursor。Cursor实际返回是一个二维的表格,有行有列,行是具体的元素,列是该元素具体的属性。整个方式和SQLite非常相似。

//可以很方便将Cursor的内容映射到ListActivity上,具体参见Android学习笔记(四十二):SQLite,ListView,ContextMenu
public class Chapter26Test1 extendsListActivity {
    private String[] INFO = new String[]{
        ContactsContract.Contacts._ID, //对于Content Provider返回数据表格而言,注意唯一标识_ID通常是必须读取的,否则很容易报错
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.Contacts.HAS_PHONE_NUMBER
    };
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        Cursor contactCursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO, null,null,null);
                                                  ListAdapter adapter = new SimpleCursorAdapter(this,
                                                  R.layout.chapter_22_test1,contactCursor,
                                                  new String[]{ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts.HAS_PHONE_NUMBER},
                                                  new int[]{R.id.c22_name,R.id.c22_gravity});
        setListAdapter(adapter); //偷偷懒,本例子直接利用了Android学习笔记(四十二)中SQLite例子中的xml
    }
}

说说Android联系人信息的组织结构及读取

这是Android给出的联系人组织结构图。分为三层。

第一层,Contact,即ContactContract.Contacts,是整合的联系人信息。

第二层,RawConact,即 ContactContract.RawContact,记录的是该联系人来自某信息源的信息,例如本地输入的,来自Google的,从微软 Exchange中导出的,或则来自某个社交网站的信息。每个RawContact记录的信息都来自同一信息源。

第三层,Data,即 ContactContract.Data,是具体的信息存储,例如记录联系人姓名,email信息,家庭电话,手机电话信息等等,每一个Data都存放一个具体的信息。在Data中的MIME TYPE说明存储信息的类型。具体在ContactContract.CommonDataKinds中定义。每个Data中有DATA1-DATA15 个字段来存储信息,各字段所代表的含义,也可以在CommonDataKinds中具体查到。

下面,我们一层一层地读取联系人信息,将更清晰地看到这个结构。要读取详细信息,对于Content Privider,关键是Uri逐层定位,才能获取信息。为了清晰表述,我们将整个路径写出来。

第一层信息,将返回联系人列表中的多个Contacts,Uri为ContactsContract.Contacts.CONTENT_URI

private String[] INFO_1= new String[]{
    ContactsContract.Contacts._ID,//这是每个row,也就是每个联系人的唯一的ID标识
    ContactsContract.Contacts.DISPLAY_NAME,
};
Cursor cursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO_1,null,null,null);

cursor是表格形式,每一个行表示一个联系人。要 读取哪些列,在第二个参数String[]中定义。可以选取那些列,在Android Reference中的ContactsContract.Contacts中的Column中可以查到。最关键的列信息为_ID,它是行,也就是每个联系人的唯一标识。除此之外,每个联系人的信息会根据旗下的RawContact进行整合,因此,我们可以查到联系的名字 ContactsContract.Contacts.DISPLAY_NAME等。

利用Contacts._ID,我们可以检索第二层的信息。

第二层信息,将返回某联系人的多个RawContacts

同样,返回表格中的列,可以查看 ContactsContract.RawContacts中查看。我们选取下面的信息,此外,如果要查看信息的来源,例如来自com.google,可通过RawContacts.ACCOUNT_TYPE和RawContacts.ACCOUNT_NAME两个列查看。

private String[ ] INFO_2 = {
    ContactsContract.RawContacts._ID, //这是RawContact的唯一标识
    ContactsContract.RawContacts.CONTACT_ID, //这是该RawContact关联的Contact._ID
};

通过查询全部的RawContacts,通过条件检索,要求联系人的ID为指定的某联系人。在下面的例子在managedQuery中给出了param3和param4的条件,注意参数3,如果我们有多个条件,可以用AND等逻辑符合进行表述。

Cursor cursor = managedQuery(ContactsContract.RawContacts.CONTENT_URI ,
                                                     INFO_2 ,
                                          RawContacts.CONTACT_ID + "=?" ,
                                          new String[]{String.valueOf(contactId)} ,
                                                    null);

通过RawContacts._ID,我们可以往下检索RawContacts下面各Data的信息内容。

第三层信息:将返回某RawContact的各Data的信息

可查询各列的信息见ContactsContract.Data的介绍。

private String INFO_3[] = {
    ContactsContract.Data._ID, //这是Data信息块的唯一标识
    ContactsContract.Data.CONTACT_ID, //关联第一层信息的CONTACT_ID
    ContactsContract.Data.RAW_CONTACT_ID, //关联第二层信息的RAW_IDCONTACT_ID
    ContactsContract.Data.MIMETYPE, //具体含义可查ContactsContract.CommonDataKinds
    ContactsContract.Data.DATA1, //通常读取DATA1就可以,在具体的ContactsContract.CommonDataKinds.Phone/Email等查到DATA1-DATA15的含义
    ContactsContract.Data.DATA2,
    … …
    ContactsContract.Data.DATA15,
};

读取的方式有两种。

方式一:指定定具体的Uri:

Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawId);
Uri dataUri =Uri.withAppendedPath(rawContactUri,ContactsContract.RawContacts.Data.CONTENT_DIRECTORY);
Cursor cursor = managedQuery( dataUri, INFO_3,null, null, null);

方式二:另一种是利用RawContacts_ID或者Contact_ID,通过Data.CONTENT_URI,具体方式类RawContacts的检索。

Cursor cursor = managedQuery(ContactsContract.Data.CONTENT_URI ,
                                                     INFO_3 ,
                                          ContactsContract.Data.RAW_CONTACT_ID + "=?" ,
                                          new String[]{String.valueOf(rawId)} ,
                                                    null);

总结一下架构图。实际上Android的联系人提供了多种URI的的查询方式,具体参加Android的reference。

Android Contacts (android通讯录读取)-content provider的更多相关文章

  1. Android开发学习之路--Content Provider之初体验

    天气说变就变,马上又变冷了,还好空气不错,阳光也不错,早起上班的车上的人也不多,公司来的同事和昨天一样一样的,可能明天会多一些吧,那就再来学习android吧.学了两个android的组件,这里学习下 ...

  2. Android 内容提供器(Content Provider)介绍

    内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性.目前,使用内容 ...

  3. Android开发-API指南-创建 Content Provider

    Creating a Content Provider 英文原文:http://developer.android.com/guide/topics/providers/content-provide ...

  4. Android 数据存储04之Content Provider

    Content Provider 版本 修改内容 日期 修改人 V1.0 原始版本 2013/2/25 skywang 1 URI 通用资源标志符(Universal Resource Identif ...

  5. Android开发-API指南-Content Provider基础

    Content Provider Basics 英文原文:http://developer.android.com/guide/topics/providers/content-provider-ba ...

  6. 【转】Pro Android学习笔记(六):了解Content Provider(中)

    Content Provider的架构 Authority类似web中的域名,每个content provider会通过AndroidManifest.xml向系统注册authority,如下.其中n ...

  7. 浅析调用android的content provider(一)

            在Android下,查询联系人.通话记录等,需要用到content provider.但是,调用content provider时,Android框架内部是如何做的呢?这一系列文章就是 ...

  8. Android Content Provider Guides

    Android Content Provider Guides Content Providers管理对结构化数据集的访问.它们包装数据,并且提供一种定义数据安全的机制. Content provid ...

  9. 6、Android Content Provider测试

    如果你的应用中使用了Content Provider来与其他应用进行数据交互,你需要对Content Provider进行测试来确保正常工作. 创建Content Provider整合测试 在Andr ...

随机推荐

  1. hashMap底层put和get方法逻辑

    1.hashmap put方法的实现: public V put(K key, V value) { if (key == null) return putForNullKey(value); int ...

  2. Hiking 分类: 比赛 HDU 函数 2015-08-09 21:24 3人阅读 评论(0) 收藏

    Hiking Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Subm ...

  3. 第十二届浙江省大学生程序设计大赛-May Day Holiday 分类: 比赛 2015-06-26 14:33 10人阅读 评论(0) 收藏

    May Day Holiday Time Limit: 2 Seconds Memory Limit: 65536 KB As a university advocating self-learnin ...

  4. LTE切换与TAU问题

    假如有两个LTE基站A B(同频组网) AB TAC不同 且添加了双向邻区关系 现终端开机重选至A然后往B方向移动 是先切换呢?还是先进性TAU更新 这个没有影响,,TAU并非需要在IDLE状态下才能 ...

  5. PowerShell处理RSS信息

    转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 环境:Windows Server 2012 EN(解决PowerShell控制台中文乱码问题:方 ...

  6. SQL与C#结合完整修改 删除信息

    --SQl中--建立ren的数据库,插入一条信息 create database ren go use ren go create table xinxi ( code ) primary key,- ...

  7. 各操作系统配置java环境变量

    Windows 1. JAVA_HOME -->>  E:\java-tools\Java\JDK8_64\jdk1.8.0_77 2. path -->> %JAVA_HOM ...

  8. 【Thread】多线程的异常处理?

    线程中处理异常是个头疼的问题,在异步的代码中,如何将异常捕获. 捕获异常后,将异常反馈给开发者,或用户.一般来说,反馈给开发者,多数方式在是日志中打印异常日志:而反馈给用户,多数是在界面上友好提示(比 ...

  9. number_format

    number_format — 以千位分隔符方式格式化一个数字 说明 string number_format ( float $number [, int $decimals = 0 ] ) str ...

  10. BZOJ 1565 植物大战僵尸(最大权闭合图)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1565 题意:植物大战僵尸,一个n*m的格子,每 个格子里有一个植物,每个植物有两个属性: ...