基础总结篇:ContentProvider之读写联系人
在Android中,ContentProvider是一种数据包装器,适合在不同进程间实现信息的共享。
例如,在Android中SQLite数据库是一个典型的数据源,我们可以把它封装到ContentProvider中,这样就可以很好的为其他应用提供信息共享服务。其他应用在访问ContentProvider时,可以使用一组类似REST的URI的方式进行数据操作,大大简化了读写信息的复杂度。例如,如果要从封装图书数据库的ContentProvider获取一组图书,需要使用类似以下形式的URI:
content://com.scott.book.BookProvider/books
而要从图书数据库中获取指定图书(比如23号图书),需要使用类似以下形式的URI:
content://com.scott.book.BookProvider/books/23
注:ContentProvider是一个抽象类,定义了一系列操作数据的方法模板,BookProvider需要实现这些方法,实现图书信息的各种操作。
那么,现在知道了具体的URI之后,我们又如何操作进而取得数据呢?
此时,我们就要了解ContentResolver这个类,它跟ContentProvider是对应的关系,我们正是通过它来与ContentProvider进行数据交换的。android.content.Context类为我们定义了getContentResolver()方法,用于获取一个ContentResolver对象,如果我们在运行期可以通过getContext()获取当前Context实例对象,就可以通过这个实例对象所提供的getContentResolver()方法获取到ContentResolver类型的实例对象,进而可以操作对应的数据。
下面我们就通过联系人实例对这种机制进行演示。
在Android中,联系人的操作都是通过一个统一的途径来读写数据的,我们打开/data/data/com.android.providers.contacts可以看到联系人的数据源:
有兴趣的朋友可以导出这个文件,用专业的工具软件打开看一下表结构。
对这个SQLite类型的数据源的封装后,联系人就以ContentProvider的形式为其他应用进程提供联系人的读写服务,我们就可以顺利成章的操作自己的联系人信息了。
为了方便测试,我们先添加两个联系人到数据源中,如图所示:
我们看到,每个联系人都有两个电话号码和两个邮箱账号,分别为家庭座机号码、移动手机号码、家庭邮箱账号和工作邮箱账号。当然在添加联系人时有很多其他信息,我们这里都没有填写,只选择了最常用的电话和邮箱,主要是方便演示这个过程。
在演示代码之前,我们需要了解一下android.provider.ContactsContract这个类(注:在较早的版本中是android.provider.Contacts这个类,不过现在已被废弃,不建议使用),它定义了各种联系人相关的URI和每一种类型信息的属性信息:
有兴趣的朋友还可以读一下源代码,不过比较多,而且内部类使用的特别多,读起来有一定的困难,还是要做好心理准备。
下面我们通过一个项目,来演示一下联系人操作的具体过程。新建一个名为provider的项目,创建一个名为ContactsReadTest的测试用例,如下:
[java] view plain copy print ?- packagecom.scott.provider;
- importjava.util.ArrayList;
- importandroid.content.ContentResolver;
- importandroid.database.Cursor;
- importandroid.net.Uri;
- importandroid.provider.ContactsContract;
- importandroid.test.AndroidTestCase;
- importandroid.util.Log;
- publicclassContactsReadTestextendsAndroidTestCase{
- privatestaticfinalStringTAG="ContactsReadTest";
- //[content://com.android.contacts/contacts]
- privatestaticfinalUriCONTACTS_URI=ContactsContract.Contacts.CONTENT_URI;
- //[content://com.android.contacts/data/phones]
- privatestaticfinalUriPHONES_URI=ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
- //[content://com.android.contacts/data/emails]
- privatestaticfinalUriEMAIL_URI=ContactsContract.CommonDataKinds.Email.CONTENT_URI;
- privatestaticfinalString_ID=ContactsContract.Contacts._ID;
- privatestaticfinalStringDISPLAY_NAME=ContactsContract.Contacts.DISPLAY_NAME;
- privatestaticfinalStringHAS_PHONE_NUMBER=ContactsContract.Contacts.HAS_PHONE_NUMBER;
- privatestaticfinalStringCONTACT_ID=ContactsContract.Data.CONTACT_ID;
- privatestaticfinalStringPHONE_NUMBER=ContactsContract.CommonDataKinds.Phone.NUMBER;
- privatestaticfinalStringPHONE_TYPE=ContactsContract.CommonDataKinds.Phone.TYPE;
- privatestaticfinalStringEMAIL_DATA=ContactsContract.CommonDataKinds.Email.DATA;
- privatestaticfinalStringEMAIL_TYPE=ContactsContract.CommonDataKinds.Email.TYPE;
- publicvoidtestReadContacts(){
- ContentResolverresolver=getContext().getContentResolver();
- Cursorc=resolver.query(CONTACTS_URI,null,null,null,null);
- while(c.moveToNext()){
- int_id=c.getInt(c.getColumnIndex(_ID));
- StringdisplayName=c.getString(c.getColumnIndex(DISPLAY_NAME));
- Log.i(TAG,displayName);
- ArrayList<String>phones=newArrayList<String>();
- ArrayList<String>emails=newArrayList<String>();
- Stringselection=CONTACT_ID+"="+_id;//the'where'clause
- //获取手机号
- inthasPhoneNumber=c.getInt(c.getColumnIndex(HAS_PHONE_NUMBER));
- if(hasPhoneNumber>0){
- Cursorphc=resolver.query(PHONES_URI,null,selection,null,null);
- while(phc.moveToNext()){
- StringphoneNumber=phc.getString(phc.getColumnIndex(PHONE_NUMBER));
- intphoneType=phc.getInt(phc.getColumnIndex(PHONE_TYPE));
- phones.add(getPhoneTypeNameById(phoneType)+":"+phoneNumber);
- }
- phc.close();
- }
- Log.i(TAG,"phones:"+phones);
- //获取邮箱
- Cursoremc=resolver.query(EMAIL_URI,null,selection,null,null);
- while(emc.moveToNext()){
- StringemailData=emc.getString(emc.getColumnIndex(EMAIL_DATA));
- intemailType=emc.getInt(emc.getColumnIndex(EMAIL_TYPE));
- emails.add(getEmailTypeNameById(emailType)+":"+emailData);
- }
- emc.close();
- Log.i(TAG,"emails:"+emails);
- }
- c.close();
- }
- privateStringgetPhoneTypeNameById(inttypeId){
- switch(typeId){
- caseContactsContract.CommonDataKinds.Phone.TYPE_HOME:return"home";
- caseContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:return"mobile";
- caseContactsContract.CommonDataKinds.Phone.TYPE_WORK:return"work";
- default:return"none";
- }
- }
- privateStringgetEmailTypeNameById(inttypeId){
- switch(typeId){
- caseContactsContract.CommonDataKinds.Email.TYPE_HOME:return"home";
- caseContactsContract.CommonDataKinds.Email.TYPE_WORK:return"work";
- caseContactsContract.CommonDataKinds.Email.TYPE_OTHER:return"other";
- default:return"none";
- }
- }
- }
- <!--配置测试设备的主类和目标包-->
- <instrumentationandroid:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.scott.provider"/>
- <!--配置测试要使用的类库-->
- <uses-libraryandroid:name="android.test.runner"/>
- <!--读取联系人-->
- <uses-permissionandroid:name="android.permission.READ_CONTACTS"/>
看来联系人里的信息都被我们准确无误的读取出来了。
如果我们在一个Activity里运行读取联系人的代码,不仅可以使用ContentResolver直接进行读取操作(即查询),还可以使用Activity提供的managedQuery方法方便的实现同样的效果,我们来看一下这个方法的具体代码:
[java] view plain copy print ?- publicfinalCursormanagedQuery(Uriuri,
- String[]projection,
- Stringselection,
- String[]selectionArgs,
- StringsortOrder)
- {
- Cursorc=getContentResolver().query(uri,projection,selection,selectionArgs,sortOrder);
- if(c!=null){
- startManagingCursor(c);
- }
- returnc;
- }
接下来我们将要尝试将一个联系人信息添加到系统联系人的数据源中,实现对联系人的写入操作。我们新建一个名为ContactsWriteTest的测试用例,如下:
[java] view plain copy print ?- packagecom.scott.provider;
- importjava.util.ArrayList;
- importandroid.content.ContentProviderOperation;
- importandroid.content.ContentProviderResult;
- importandroid.content.ContentResolver;
- importandroid.net.Uri;
- importandroid.provider.ContactsContract;
- importandroid.test.AndroidTestCase;
- importandroid.util.Log;
- publicclassContactsWriteTestextendsAndroidTestCase{
- privatestaticfinalStringTAG="ContactsWriteTest";
- //[content://com.android.contacts/raw_contacts]
- privatestaticfinalUriRAW_CONTACTS_URI=ContactsContract.RawContacts.CONTENT_URI;
- //[content://com.android.contacts/data]
- privatestaticfinalUriDATA_URI=ContactsContract.Data.CONTENT_URI;
- privatestaticfinalStringACCOUNT_TYPE=ContactsContract.RawContacts.ACCOUNT_TYPE;
- privatestaticfinalStringACCOUNT_NAME=ContactsContract.RawContacts.ACCOUNT_NAME;
- privatestaticfinalStringRAW_CONTACT_ID=ContactsContract.Data.RAW_CONTACT_ID;
- privatestaticfinalStringMIMETYPE=ContactsContract.Data.MIMETYPE;
- privatestaticfinalStringNAME_ITEM_TYPE=ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE;
- privatestaticfinalStringDISPLAY_NAME=ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME;
- privatestaticfinalStringPHONE_ITEM_TYPE=ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
- privatestaticfinalStringPHONE_NUMBER=ContactsContract.CommonDataKinds.Phone.NUMBER;
- privatestaticfinalStringPHONE_TYPE=ContactsContract.CommonDataKinds.Phone.TYPE;
- privatestaticfinalintPHONE_TYPE_HOME=ContactsContract.CommonDataKinds.Phone.TYPE_HOME;
- privatestaticfinalintPHONE_TYPE_MOBILE=ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;
- privatestaticfinalStringEMAIL_ITEM_TYPE=ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
- privatestaticfinalStringEMAIL_DATA=ContactsContract.CommonDataKinds.Email.DATA;
- privatestaticfinalStringEMAIL_TYPE=ContactsContract.CommonDataKinds.Email.TYPE;
- privatestaticfinalintEMAIL_TYPE_HOME=ContactsContract.CommonDataKinds.Email.TYPE_HOME;
- privatestaticfinalintEMAIL_TYPE_WORK=ContactsContract.CommonDataKinds.Email.TYPE_WORK;
- privatestaticfinalStringAUTHORITY=ContactsContract.AUTHORITY;
- publicvoidtestWriteContacts()throwsException{
- ArrayList<ContentProviderOperation>operations=newArrayList<ContentProviderOperation>();
- ContentProviderOperationoperation=ContentProviderOperation.newInsert(RAW_CONTACTS_URI)
- .withValue(ACCOUNT_TYPE,null)
- .withValue(ACCOUNT_NAME,null)
- .build();
- operations.add(operation);
- //添加联系人名称操作
- operation=ContentProviderOperation.newInsert(DATA_URI)
- .withValueBackReference(RAW_CONTACT_ID,0)
- .withValue(MIMETYPE,NAME_ITEM_TYPE)
- .withValue(DISPLAY_NAME,"ScottLiu")
- .build();
- operations.add(operation);
- //添加家庭座机号码
- operation=ContentProviderOperation.newInsert(DATA_URI)
- .withValueBackReference(RAW_CONTACT_ID,0)
- .withValue(MIMETYPE,PHONE_ITEM_TYPE)
- .withValue(PHONE_TYPE,PHONE_TYPE_HOME)
- .withValue(PHONE_NUMBER,"01034567890")
- .build();
- operations.add(operation);
- //添加移动手机号码
- operation=ContentProviderOperation.newInsert(DATA_URI)
- .withValueBackReference(RAW_CONTACT_ID,0)
- .withValue(MIMETYPE,PHONE_ITEM_TYPE)
- .withValue(PHONE_TYPE,PHONE_TYPE_MOBILE)
- .withValue(PHONE_NUMBER,"13034567890")
- .build();
- operations.add(operation);
- //添加家庭邮箱
- operation=ContentProviderOperation.newInsert(DATA_URI)
- .withValueBackReference(RAW_CONTACT_ID,0)
- .withValue(MIMETYPE,EMAIL_ITEM_TYPE)
- .withValue(EMAIL_TYPE,EMAIL_TYPE_HOME)
- .withValue(EMAIL_DATA,"[email protected]")
- .build();
- operations.add(operation);
- //添加工作邮箱
- operation=ContentProviderOperation.newInsert(DATA_URI)
- .withValueBackReference(RAW_CONTACT_ID,0)
- .withValue(MIMETYPE,EMAIL_ITEM_TYPE)
- .withValue(EMAIL_TYPE,EMAIL_TYPE_WORK)
- .withValue(EMAIL_DATA,"[email protected]")
- .build();
- operations.add(operation);
- ContentResolverresolver=getContext().getContentResolver();
- //批量执行,返回执行结果集
- ContentProviderResult[]results=resolver.applyBatch(AUTHORITY,operations);
- for(ContentProviderResultresult:results){
- Log.i(TAG,result.uri.toString());
- }
- }
- }
当然,这个也不能忘了配置写入联系人的权限声明:
[html] view plain copy print ?- <!--写入联系人-->
- <uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/>
更多相关文章
- Android官方命令深入分析之bmgr
- Android性能优化之内存篇
- 学习到的有关android的知识点 单元测试等(1)
- Android(安卓)Studio学习-连接真机测试教学
- Android(安卓)异步更新UI----handler+thread
- Android(安卓)数据库的简单使用
- 【Android】第4章(5) 示例--列出手机上的所有联系人
- Android并发修改异常:java.util.ConcurrentModificationException
- Android(安卓)应用安装过程分析