Android关于Content Provider的电话本小研究

来源:互联网 发布:美工刀架图片 编辑:程序博客网 时间:2024/05/16 23:53

    读文档读到Content Provider一节,文档中提供了获取通讯录的数据的方法,所以实践了一下,发现了很多问题。

    Content Provider存储数据的模型是基于一张表格的,其实也就是数据库,每一个Content Provider都提供一个URI来标识这个data set模型,这个URI提供一个以"content://"开头的字符串,来表明此data set是在哪个Content Provider控制之下的,这个URI在类中通常定义为public static final CONTENT_URI = "content://xxxxxx ",在实现自己的Content Provider的时候,通常也定义自己的CONTENT_URI.比如说在sdk文档中的notepad例子中的ContentProvider中就定义了自己的Content URI标识: public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");

 

     文档中提到,电话本的数据模型可能是被定义为这样子的:

_IDNUMBERNUMBER_KEYLABELNAMETYPE13(425) 555 6677425 555 6677Kirkland officeBully PulpitTYPE_WORK44(212) 555-1234212 555 1234NY apartmentAlan VainTYPE_HOME45(212) 555-6657212 555 6657Downtown officeAlan VainTYPE_MOBILE53201.555.4433201 555 4433Love NestRex CarsTYPE_HOME
    其中每一条记录都有一个_ID唯一的标识,这个ID可以在不同的数据库表格中起关联作用。

 

    一般,我们访问Content Provider的时候不是直接访问,而是通过ContentResolver来方式,contentResolver可以通过getContentResolver()得到,一般resolver的query返回一个Cursor对象,这个Cursor对象就是操作遍历上述表格的工具了,他可以从行到行,也可以从列到列,从而访问到其中的数据,在使用实例的时候大家会体会到其作用。

   

    说一下文档中提供的通过Content Resolver查询电话本的方式,需要注意的是访问隐私信息的app需要先在manifest.xml中声明访问权限,在manifest节点内加入

    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

否则会出现SecurityException。

     访问代码如下:

 

import android.provider.Contacts.People;
import android.database.Cursor;

// Form an array specifying which columns to return.
String[] projection = new String[] {
                             
People._ID,
                             
People._COUNT,
                             
People.NAME,
                             
People.NUMBER
                         
};

// Get the base URI for the People table in the Contacts content provider.
Uri contacts =  People.CONTENT_URI;

// Make the query.
Cursor managedCursor = managedQuery(contacts,
                         projection
, // Which columns to return
                         
null,       // Which rows to return (all rows)
                         
null,       // Selection arguments (none)
                         
// Put the results in ascending order by name
                         
People.NAME + " ASC");

    然后,通过返回的Cursor来访问数据就可以了,代码:

 

 if (cur.moveToFirst()) {

       
String name;
       
String phoneNumber;
       
int nameColumn = cur.getColumnIndex(People.NAME);
       
int phoneColumn = cur.getColumnIndex(People.NUMBER);
       
String imagePath;
   
       
do {
           
// Get the field values
            name
= cur.getString(nameColumn);
            phoneNumber
= cur.getString(phoneColumn);
           
           
// Do something with the values.
           
...

       
} while (cur.moveToNext());

   
}

这样就取回了数据。

 

问题是,我们所用的方法中,有很多的方法和类已经被废弃了,比如import android.provider.Contacts.Phones;就已经被废弃,我想做的就是不用这些废弃的类和方法,而是采用其提供的新的方法,通过api的提示,新的类可以参考ContactsContract , 打开这个类我们可以看到,这个类定义了许多contact相关的拓展类,包括ContactsContract.Data,ContactsContract.RawContacts ,

ContactsContract.Contacts 等等相关的类,我们可以知道这个电话本的数据库看一下:

 

 

   打开eclipse,启动模拟器,window-> show view-> other -> android -> file exploer打开文件浏览器窗口,定位到 data->data->com.android.providers.contacts->database文件夹,找到contact2.db 点击右上方的导出按钮导出此数据库文件

 

 

SQLite数据库的工具打开(比如SQLite Expert Personal 3),可以看到其中的表和视图,注意这里我们的模拟器是2.1版本,对比apicontactsContract类中的拓展类和这里的表格不难发现,其实这些类大致对应数据库的表格,至于为什么电话本的数据库的表格要这样分,而不是像上面的那个表格那么简单可以自己体会,其功能理念不同。   

 

       

 

 上面的表格中每个表格都有各自的信息分类,电话号码和姓名是不在一个表格中的,这个就给我们的数据获取工作带来了一定的困难,我们可以定位到下面的

 view_v1_phones视图

 

  

 

可以看到这个视图就将我们需要的基本的numbername合并在了一起,获取的话肯定更方便,但是,api中我们看不到针对此视图的Content Provider,取数据的话只能从两个表格利用查询条件取,可以点击这个视图的Design选项卡,读一下其中的sql语句发现这个视图也是将几个table合并在一起的。可以根据这个思想来用content Resolver从两个表格分表读数据然后合并(根据Phone_lookupname_lookupiddata中的id相等比较),具体方法应该能体会到。一开始我就用的这种方法,觉得实在没废弃的方法好用。

 

   注意到这个视图带着v1的字样,我猜想可能是兼容的旧的数据库设计,又看到api文档中的ContactsContract类是从api 5开始的,所以启动1.6的模拟器,再次导出这个数据库文件contacts.db,注意,这里就没有2的字样了,打开这个数据库果然发现,其实2版本的数据库中的view其实是1版本中的数据库的一个兼容而已,旧的类和方法在新版本中大概也就是操作这些view来完成的。

    

   

纠结良久,我还是决定用被废弃的api。。。