Android-ContentProvider读取/新增/操作系统联系人数据
想要访问Android操作系统的ContentProvider就需要明白以下原理:
在Android操作系统里面的 /packsges/目录:
apps: 很多的系统应用,例如:联系人,浏览器,音乐播放器,设置,相机 ......
............
providers:系统对外暴露的ContentProvider:
这样就明白了,Android操作系统里面的应用(apps),是访问系统对外暴露的ContentProvider(providers)
先在模拟器,添加联系人:
既然说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对外暴露)
阅读 com.android.providers.contacts 数据库与表
Android操作系统的文件系统目录/data/data/com.android.contacts,是访问/data/data/com.android.providers.contacts(内容提供者应用)
所以需要阅读/data/data/com.android.providers.contacts(内容提供者应用)的数据库:
打开 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表:
data表:
mimetypes表:
阅读 com.android.providers.contacts AndroidManifest.xml,和ContactsProvider2.java
apps目录的contacts应用,是访问provider目录的provider.contacts应用,所以要阅读Android操作系统源码-->packages/providers/ContactsProvider(内容提供者)
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/data Cursor 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-ContentProvider读取/新增/操作系统联系人数据的更多相关文章
- 【Android Developers Training】 100. 使用Intent修改联系人数据
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- Android ContentProvider和getContentResolver
安卓系统中的数据库SqlLite操作和java中mysql的数据库操作很不一样,造成这样的原因是因为在安卓中数据库是属于进程的不存在数据库客户端,也不存在数据库服务器. 关于SqlLite数据库的文章 ...
- Android ContentProvider、ContentResolver和ContentObserver的使用
1.ContentProvider.ContentResolver和ContentObserver ContentProvider是Android的四大组件之中的一个,可见它在Android中的作用非 ...
- Android ContentProvider基本用法
转自:https://www.jianshu.com/p/601086916c8f 一.基本概念 ContentProvider是Android系统中提供的专门用户不同应用间进行数据共享的组件,提供了 ...
- Android开发7:简单的数据存储(使用SharedPreferences)和文件操作
前言 啦啦啦~大家好,又见面啦~ 本篇博文讲和大家一起完成一个需要注册.登录的备忘录的,一起学习 SharedPreferences 的基本使用,学习 Android 中常见的文件操作方法,复习 An ...
- Android Contacts (android通讯录读取)-content provider
Content Provider 在数据处理中,Android通常使用Content Provider的方式.Content Provider使用Uri实例作为句柄的数据封装的,很方便地访问地进行数据 ...
- Android ContentProvider和Uri详解 (绝对全面)
ContentProvider的基本概念 : 1.ContentProvider为存储和读取数据提供了统一的接口 2.使用ContentProvider,应用程序可以实现数据共享 3.andr ...
- Android ContentProvider 简介
当在系统中部署一个又一个Android应用之后,系统里将会包含多个Android应用,有时候就需要在小同的应用之问芡亭数据,比如现在有一个短信接收应用,用户想把接收到的陌生短信的发信人添加到联系人管理 ...
- Android编程中的5种数据存储方式
Android编程中的5种数据存储方式 作者:牛奶.不加糖 字体:[增加 减小] 类型:转载 时间:2015-12-03我要评论 这篇文章主要介绍了Android编程中的5种数据存储方式,结合实例形式 ...
随机推荐
- 手把手教你使用node-inspector调试nodejs
最近再看nodejs,这个东西是运行在服务端的,也就是说我们在客户端看不到相应的js代码,那么怎么调试了?目前主流的方法有三种.第一是采用node-inspector.第二种采用nodejs内置的调试 ...
- 记录两个python的小问题
使用python也前前后后也一个月的样子,记录两个一直没注意的问题. 1. 元组的使用(拼接字符串) 直接看下面的代码: >>> kel = 'some','strings' > ...
- Delphi 画箭头
procedure TForm1.Line(x, y, x2, y2: integer); begin canvas.MoveTo(x, y); canvas.LineTo(x2, y2); end; ...
- tornado异步编程
说明 以下的例子都有2个url,一个是耗时的请求,一个是可以立刻返回的请求,,我们希望的是访问立刻返回结果的请求不会被其他耗时请求影响 非异步处理 现在我们请求sleep然后同时请求justnow,发 ...
- 【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 15—Anomaly Detection异常检测
Lecture 15 Anomaly Detection 异常检测 15.1 异常检测问题的动机 Problem Motivation 异常检测(Anomaly detection)问题是机器学习算法 ...
- node模块示例
来源于慕课网课程:http://www.imooc.com/video/6701 (视频) 模块的流程图如下: 做一个学校的模块示例 建一个学生的js studet.js function add(s ...
- 关于 jdbc 的错误
- go grpc
https://godoc.org/google.golang.org/grpc go get google.golang.org/grpc go get -a github.com/golang/p ...
- xbstream 备份恢复
xbstream -x < ./backs/backup.xbstream -C /dbnode/data/ innobackupex --defaults-file=/dbnode/etc/ ...
- EMC存储同时分配空间到两台服务器路径不一致-双机盘符不一致
以下方式将i盘盘符换成g盘,g盘盘符换成i emcpadm rename -s emcpoweri -t emcpowerj emcpadm rename -s emcpowerg -t emcpow ...