Android-读取/新增/操作系统联系人数据

书史足自悦,安用勤与劬。这篇文章主要讲述Android-读取/新增/操作系统联系人数据相关的知识,希望能为你提供帮助。
想要访问android操作系统的ContentProvider就需要明白以下原理:
 
在Android操作系统里面的 /packsges/目录:
apps: 很多的系统应用,例如:联系人,浏览器,音乐播放器,设置,相机 ......

Android-读取/新增/操作系统联系人数据

文章图片
............
providers:系统对外暴露的ContentProvider:
Android-读取/新增/操作系统联系人数据

文章图片

这样就明白了,Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers)
 
 
先在模拟器,添加联系人:
Android-读取/新增/操作系统联系人数据

文章图片

 
既然说Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers):
/data/data/com.android.contacts(放置在apps目录里面)
/data/data/com.android.providers.contacts(放置在providers目录里面)
contacts(联系人应用) 是调用  providers.contacts(内容提供者里面的数据),如图:
(为什么apps目录的contacts应用 能够访问provider目录的provider.contacts应用?,因为provider目录的provider.contacts应用通过ContentProvider对外暴露)
Android-读取/新增/操作系统联系人数据

文章图片

 
 
阅读  com.android.providers.contacts 数据库与表Android操作系统的文件系统目录/data/data/com.android.contacts,是访问/data/data/com.android.providers.contacts(内容提供者应用)
所以需要阅读/data/data/com.android.providers.contacts(内容提供者应用)的数据库:
Android-读取/新增/操作系统联系人数据

文章图片

 
打开 contacts2.db
  打开后:表非常多,视图非常多,等等, 但是只需要关注三张核心的表
1.raw_contacts(联系人唯一标识表:里面有 _id 的字段,是标识了一个联系人的唯一标识)
2.data(通过 raw_contacts 表里面的_id,查询 raw_contacts_id,就能得到查询结果)
得到查询结果后:data1字段: 联系人数据,data2字段:数据对应的分类(家庭,住宅....)
得到查询结果后:mimetype_id字段,是用来查询的mimetypes表,数据对应的(姓名,..)
3.mimetypes(通过 data 表里面的 mimetype_id,查询对应的值)
raw_contacts表:
Android-读取/新增/操作系统联系人数据

文章图片

 
data表:
Android-读取/新增/操作系统联系人数据

文章图片

 
mimetypes表:
Android-读取/新增/操作系统联系人数据

文章图片

 
 
阅读  com.android.providers.contacts AndroidManifest.xml,和ContactsProvider2.javaapps目录的contacts应用,是访问provider目录的provider.contacts应用,所以要阅读Android操作系统源码--> packages/providers/ContactsProvider(内容提供者)
Android-读取/新增/操作系统联系人数据

文章图片

 
AndroidManifest.xml
1.ContactsProvider2就是联系人的内容提供者
2.android:authorities="contacts; com.android.contacts"  Android2.2版本之前的授权contacts,后面为了考虑兼容性就  ; com.android.contacts,这样就两个授权都可以使用了,相当于Web服务器项目的两个域名,都可以访问服务器
3.android:exported="true" 允许对外输出
4.设定被访问的权限  android:readPermission="android.permission.READ_CONTACTS" 联系人内容提供者读取权限
    android:writePermission="android.permission.WRITE_CONTACTS"  联系人内容提供者修改权限
< provider android:name="ContactsProvider2" android:authorities="contacts; com.android.contacts" android:label="@string/provider_label" android:multiprocess="false" android:exported="true" android:readPermission="android.permission.READ_CONTACTS" android:writePermission="android.permission.WRITE_CONTACTS"> < path-permission android:pathPrefix="/search_suggest_query" android:readPermission="android.permission.GLOBAL_SEARCH" /> < path-permission android:pathPrefix="/search_suggest_shortcut" android:readPermission="android.permission.GLOBAL_SEARCH" /> < path-permission android:pathPattern="/contacts/.*/photo" android:readPermission="android.permission.GLOBAL_SEARCH" /> < grant-uri-permission android:pathPattern=".*" /> < /provider>

 
 
ContactsProvider2.java
首先要找到的就是Uri,所以搜索UriMatcher的matcher.addURI
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", CONTACTS_LOOKUP_DISPLAY_PHOTO); matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", CONTACTS_LOOKUP_ENTITIES); matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", CONTACTS_LOOKUP_ID_ENTITIES); matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", CONTACTS_LOOKUP_STREAM_ITEMS); matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", CONTACTS_LOOKUP_ID_STREAM_ITEMS); matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", CONTACTS_AS_MULTI_VCARD); matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", CONTACTS_STREQUENT_FILTER); matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); matcher.addURI(ContactsContract.AUTHORITY, "contacts/delete_usage", CONTACTS_DELETE_USAGE); matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA);

 
有规律,通常情况下,matcher.addURI(授权, path, code),第二个参数 path 和数据库表名对应的
我首先要查询,raw_contacts 表,所以找到查询这个表的 Uri :matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
然后还要查询,data 表,所要要查询这个表的 Uri :
注意用这个关联查询: matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA);
这个不是关联查询: matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);

写入数据需要, 往raw_contacts表增加一条数据,作为唯一标示 matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
写入数据需要,不需要关联查询的Uir,需要写入到Data表:matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
 
读取 --> > Android操作系统联系人内容提供者应用里面的联系人数据: 增加数据到    Android操作系统联系人内容提供者应用里面  
package liudeli.cp.client; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class ContactsActivity extends Activity {private final String TAG= ContactsActivity.class.getSimpleName(); private EditText name; private EditText phone; private EditText email; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contacts); name = findViewById(R.id.et_name); phone = findViewById(R.id.et_phone); email = findViewById(R.id.et_email); }/** * 获取 /data/data/com.android.providers.contacts应用(内容提供者暴露的联系人数据) *packages/providers/com.android.providers.contacts应用(内容提供者暴露的联系人数据) * @param view */ public void readContacts(View view) { /** *复制com.android.providers.contacts应用的Uri *matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); *matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA); * *授权:android:authorities="contacts; com.android.contacts" */ Uri rawContactsURI = Uri.parse("content://com.android.contacts/raw_contacts"); Uri rawContactsByIdDataURI = Uri.parse("content://com.android.contacts/raw_contacts/#/data"); // 拿到内容解决者(ContentResolver) ContentResolver contentResolver = getContentResolver(); /** * 使用内容解决者 读取 操作系统联系人内容提供者应用raw_contacts表 */ Cursor cursor = contentResolver.query(rawContactsURI, new String[]{"_id"}, null, null , null); while (cursor.moveToNext()) { // cursor.getInt(0); int _id = cursor.getInt(cursor.getColumnIndex("_id")); Log.d(TAG, "_id" + _id); /** * 使用内容解决者 读取 操作系统联系人内容提供者应用data表 (根据raw_contacts表的_id 去查询) */ // 把raw_contacts表的_id 写到 rawContactsByIdDataURI2里面去 // 把_id写到...raw_contacts/#/data 的# // 第一种方式 结果为:content://com.android.contacts/raw_contacts/4#/data // 考虑到 操作系统的联系人内容提供者不是ContentUris.parseId(uri),所以用第二种拼接方式 // Uri rawContactsByIdDataURI2 = ContentUris.withAppendedId(rawContactsByIdDataURI, _id); // 第二种方式 是直接拼接 Uri rawContactsByIdDataURI2 = Uri.parse("content://com.android.contacts/raw_contacts/"+_id+"/data"); // Log.d(TAG, "rawContactsByIdDataURI2:" + rawContactsByIdDataURI2.toString()); // 结果 content://com.android.contacts/raw_contacts/4/dataCursor dataCursor = contentResolver.query(rawContactsByIdDataURI2, new String[]{}, null, null, null, null); /** * 注意:?? 由于content://com.android.contacts/raw_contacts/#/data这是表关联查询 *所以查询出来的字段,我不知道,这系统去关联查询的,所以打印出来看看 */ /*String[] columnNames = dataCursor.getColumnNames(); for (String columnName : columnNames) { Log.d(TAG, "关联查询Data表 的所有字段" + columnName); }*/ /** * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段sort_key * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段photo_uri * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段status_label * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段status_ts * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段status_res_package * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段name_verified * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段display_name * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段last_time_used * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段mimetype * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonebook_label_alt * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data6 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段version * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段photo_id * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data3 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段custom_ringtone * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段times_contacted * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段account_type_and_data_set * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段dirty * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data7 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data15 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段raw_contact_is_user_profile * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_set * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonebook_label * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data10 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段res_package * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段account_type * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data11 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段display_name_alt * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段lookup * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonetic_name * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段last_time_contacted * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_last_updated_timestamp * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data13 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段in_visible_group * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段chat_capability * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data9 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_sync1 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段sort_key_alt * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_presence * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_version * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonetic_name_style * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段name_raw_contact_id * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段raw_contact_id * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段send_to_voicemail * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data4 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data12 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_status * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_status_label * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段pinned * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段status_icon * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段status * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data1 * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonebook_bucket * 12-15 22:45:46.355 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_sync2 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_status_res_package * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段in_default_directory * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段_id * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段is_super_primary * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data5 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_id * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data8 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段is_primary * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_sync4 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段has_phone_number * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段display_name_source * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段photo_file_id * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data_sync3 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data14 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_status_ts * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段phonebook_bucket_alt * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段mode * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段data2 * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段group_sourceid * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段starred * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段photo_thumb_uri * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段times_used * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_status_icon * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段contact_chat_capability * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段account_name * 12-15 22:45:46.356 4432-4432/liudeli.cp.client D/ContactsActivity: 关联查询Data表 的所有字段sourceid */Cursor dataCursor2 = contentResolver.query(rawContactsByIdDataURI2, new String[]{"data1", "data2", "mimetype"}, null, null, null, null); while (dataCursor2.moveToNext()) { String data1 = dataCursor2.getString(0); String data2 = dataCursor2.getString(1); String mimetype = dataCursor2.getString(2); // Log.d(TAG, "data1" + data1 + " ,data2:" + data2 + " ,mimetype:" + mimetype); StringBuilder sb = new StringBuilder(); /** * mimetypes表: * vnd.android.cursor.item/name * vnd.android.cursor.item/phone_v2 * vnd.android.cursor.item/email_v2 * ... */ if ("vnd.android.cursor.item/name".equals(mimetype)) { // 是姓名 if ("1".equals(data2)) { // data2 == 1是家庭相关 // Log.i(TAG, "家庭姓名:" + data1); sb.append("家庭姓名:" + data1 + ","); } else { // Log.i(TAG, "姓名:" + data1); sb.append("姓名:" + data1 + ","); } } else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) { // 是手机号码 if ("1".equals(data2)) { // data2 == 1是家庭相关 // Log.i(TAG, "家庭号码:" + data1); sb.append("家庭号码:" + data1 + ","); } else { // Log.i(TAG, "号码:" + data1); sb.append("号码:" + data1 + ","); } } else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) { // 是邮箱 if ("1".equals(data2)){ // data2 == 1是家庭相关 // Log.i(TAG, "家庭邮箱" + data1); sb.append("家庭邮箱" + data1 + ","); } else { // Log.i(TAG, "邮箱" + data1); sb.append("邮箱" + data1 + ","); } }Log.i(TAG, "联系人:" + sb.toString()); } } }/** * 写入 /data/data/com.android.providers.contacts应用(内容提供者暴露的联系人数据) *packages/providers/com.android.providers.contacts应用(内容提供者暴露的联系人数据) * @param view */ public void insertContacts(View view) {/** *复制com.android.providers.contacts应用的Uri *matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); *matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); * *授权:android:authorities="contacts; com.android.contacts" */ Uri rawContactsURI = Uri.parse("content://com.android.contacts/raw_contacts"); Uri dataUri = Uri.parse("content://com.android.contacts/data"); if (!TextUtils.isEmpty(name.getText()) & & !TextUtils.isEmpty(phone.getText()) & & !TextUtils.isEmpty(email.getText())) { /** * 思路:先往raw_contacts表增加一条记录,返回Uri,通过返回的Uri,获取id *通过获取的id,在去增加data表,把id插入到data表的raw_contacts_id字段中去(建立关联关系) */// 先往raw_contacts表增加一条记录,返回Uri,通过返回的Uri,获取id // 拿到内容解决者(ContentResolver) ContentResolver contentResolver = getContentResolver(); /** * 使用内容解决者 写入到 操作系统联系人内容提供者应用raw_contacts表 */ ContentValues contentValues = new ContentValues(); Uri rawContactsTaleInsertResult = contentResolver.insert(rawContactsURI, contentValues); // 通过返回的Uri,解析id,获取id long insertResultID = ContentUris.parseId(rawContactsTaleInsertResult); contentValues.clear(); // 通过获取的id,在去增加data表,把id插入到data表的raw_contacts_id字段中去(建立关联关系) /** * mimetypes表: * vnd.android.cursor.item/name * vnd.android.cursor.item/phone_v2 * vnd.android.cursor.item/email_v2 * ... */ contentValues.put("raw_contact_id", insertResultID); contentValues.put("mimetype", "vnd.android.cursor.item/name"); // 类型区分(例如:姓名,电话,邮箱...) contentValues.put("data1", name.getText().toString()); contentResolver.insert(dataUri, contentValues); contentValues.put("raw_contact_id", insertResultID); contentValues.put("mimetype", "vnd.android.cursor.item/phone_v2"); // 类型区分(例如:姓名,电话,邮箱...) contentValues.put("data1", phone.getText().toString()); contentValues.put("data2", 1); // 类型区分(例如:家用,公司,....) contentResolver.insert(dataUri, contentValues); contentValues.put("raw_contact_id", insertResultID); contentValues.put("mimetype", "vnd.android.cursor.item/phone_v2"); // 类型区分(例如:姓名,电话,邮箱...) contentValues.put("data1", email.getText().toString()); contentValues.put("data2", 1); // 类型区分(例如:家用,公司,....) Uri insertExit = contentResolver.insert(dataUri, contentValues); Toast.makeText(this, "插入联系人完成", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "请填写完整信息", Toast.LENGTH_LONG).show(); } } }

 
Layout:
< ?xml version="1.0" encoding="utf-8"?> < RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> < Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读取联系人" android:onClick="readContacts" /> < Button android:id="@+id/bt_insert" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="写入联系人" android:onClick="insertContacts" /> < LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_below="@id/bt_insert" android:layout_margin="20dp"> < LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> < !-- 我先放置控件 --> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请输入姓名:" /> < !-- 剩下的空间给我来全部全部填充 --> < EditText android:id="@+id/et_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> < /LinearLayout> < LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> < !-- 我先放置控件 --> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请输入号码:" /> < !-- 剩下的空间给我来全部全部填充 --> < EditText android:id="@+id/et_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> < /LinearLayout> < LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> < !-- 我先放置控件 --> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请输入邮箱:" /> < !-- 剩下的空间给我来全部全部填充 --> < EditText android:id="@+id/et_email" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> < /LinearLayout> < /LinearLayout> < /RelativeLayout>

 
AndroidManifest.xml 权限:
< !-- 访问操作系统联系人内容提供者应用,需要加入的权限 android:readPermission="android.permission.READ_CONTACTS" android:writePermission="android.permission.WRITE_CONTACTS" --> < uses-permission android:name="android.permission.WRITE_CONTACTS" /> < uses-permission android:name="android.permission.READ_CONTACTS" />

 
读取的Log日志信息,在添加联系人的时候给雷军增加了很多号码,所以日志就多一些:
12-15 23:37:32.731 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:1 368-787-8767, 
12-15 23:37:32.731 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:姓名:马化腾, 
12-15 23:37:32.731 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:
12-15 23:37:32.731 5365-5365/liudeli.cp.client D/ContactsActivity: _id2
12-15 23:37:32.786 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:1 667-878-9877, 
12-15 23:37:32.786 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:家庭号码:536-5465, 
12-15 23:37:32.786 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:姓名:马云, 
12-15 23:37:32.786 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:
12-15 23:37:32.786 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:
12-15 23:37:32.786 5365-5365/liudeli.cp.client D/ContactsActivity: _id3
12-15 23:37:32.793 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:1 378-888-8989, 
12-15 23:37:32.793 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:姓名:黄光裕, 
12-15 23:37:32.793 5365-5365/liudeli.cp.client D/ContactsActivity: _id4
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:1 869-999-9999, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:家庭号码:(646) 456-56, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:(345) 345-464, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:(654) 745-7657, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:号码:575-756, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:姓名:雷军, 
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:
12-15 23:37:32.799 5365-5365/liudeli.cp.client I/ContactsActivity: 联系人:
 
效果图:
Android-读取/新增/操作系统联系人数据

文章图片

【Android-读取/新增/操作系统联系人数据】 

    推荐阅读