使用 ContentProvider 共享数据 访问与添加通讯录
来源:互联网 发布:联通怎么开通4g网络 编辑:程序博客网 时间:2024/05/16 10:59
1. 统一的数据访问方式
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。
文件的操作模式中,通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样可以对外共享数据,
但数据的访问方式会因数据存储的方式而不同,如:采用xml文件对外共享数据,需要进行xml解析来读写数据;
采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。
而使用ContentProvider共享数据的好处是统一了数据访问方式。
通俗一点,例如我要访问另一个应用怎么来描述我的需求呢?有种方式可向 Webservice 那样,统一一种描述语言,大家靠这个来互相理解。但是太麻烦了。现在的情况远远好于应用 Webservice 的场景,因为,应用们都在一部手机上,大家都归 Android 操作系统老大管。于是好办!
甲应用说中文,说:我想得到联系人“13999999” 的详细信息。
乙应用来做大洋彼岸,说:I want to get contacts, "13999999r" for more information.
丁说ri语,高呼呀嘛蝶。
这是在要求访问“通讯录”应用啊,是属于另一个应用了,在另一个进程里。难道我做一个“通信录”程序,为了要让别人访问我,我还得提供“中文”、“英文”、“ri文”三种访问模式?这没法搞了,于是由 Android 牵头,大家商议统一描述语言,于是弄出个 Uri。
那么以后这种需求 Android 规定,大家统一说一样的语言:
content://com.android.contacts/data/phones/filter/13999999
“通讯录”程序中需要提供一种对指定模式的 Uri 的解析机制,并且这种解析机制要注册在操作系统中,随时工作。
例如,只要解析到了“data/phones/filter/13999999” 这种模式,它立马截取出 “13999999” 然后再自己的持久化库中去找寻详细信息,再返回回去。
2. 继承 ContentProviter
public class PersonContentProvider extends ContentProvider;
和 Activity 一样, ContentProviter 属于 Android 的一种组件
3. 注册内容提供者
AndroidManifest.xml
<provider android:name=".PersonContentProvider"
android:authorities="wjh.android.provider.personprovider" />
android:name : 指向内容提供者的类
android:authorities : 应用中的一个唯一的字符串标识。可以将它看作域名。在本应用或其它应用中,可以通过这个域名来访问内容提供者。
4. ContentProvider 中的方法、
/**
* 其它应用可以通过此方法对内容提供者删除数据
*/
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/**
* 其它应用可以通过此方法对内容提供者添加数据
*/
public Uri insert(Uri uri, ContentValues contentValues)
/**
* 其它应用可以通过此方法对内容提供者查询数据
*/
public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3,
String arg4)
/**
* 其它应用可以通过此方法对内容提供者更新数据
*/
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
/**
* 内容类型
*/
public String getType(Uri uri) :
该方法用于返回当前Url所代表数据的MIME类型。
如果操作的数据属于集合类型,
那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,
那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。
如果要操作的数据属于非集合类型数据,
那么MIME类型字符串应该以vnd.android.cursor.item/开头,
例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,
那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
5. URI
Uri代表了要操作的数据,Uri主要包含了两部分信息:
1. 需要操作的ContentProvider
2. 对ContentProvider中的什么数据进行操作,
一个 Uri 由以下几部分组成
scheme --> content:// (此 scheme 仅表示内容提供者的 scheme)
主机名或 Authority -->wjh.android.provider.personprovider
路径 --> person/10/name
组合成一个完整的 Uri 为:content://wjh.android.provider.personprovider/person/10/name
路径虽然可以随便定义,但为了方便其它人理解,应该遵循一定的命名规则:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
将字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
UriMatcher : 用于 Uri 匹配
UriMatcher.addURI : 添加一个 Uri 匹配模式
UriMatcher,match : 匹配Uri , 返回 Boolean 。
ContentUris :用于对 uri 进行字符操作
ContentUris.withAppendedId(uri, append) : 给 uri 添加一个 ID
ContentUris.parseId : 从 Uri 中解析出 ID
6. ContentResolver : 用于操作 ContentProvider
当外部应用需要对 ContentProvider 中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,
要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。
ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
该方法用于往ContentProvider添加数据:
public Uri insert(Uri uri, ContentValues values)
该方法用于从ContentProvider删除数据:
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于更新ContentProvider中的数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于从ContentProvider中获取数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
这些方法的第一个参数为Uri,
代表要操作的ContentProvider和对其中的什么数据进行操作,
假设给定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),
那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,
操作的数据为person表中id为10的记录。
其中主机名是要访问的应用在 AndroidManifest.xml 所注册的 provider 的 authorities 属性
7. 代码示例:
应用一:内容提供者所在的应用
1, AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="wjh.android.db" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <uses-library android:name="android.test.runner" /> <activity android:name=".MainActivity" android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> <provider android:name=".PersonContentProvider" <!-- 注册内容提供者 -->android:authorities="wjh.android.provider.personprovider" /> </application> <uses-sdk android:minSdkVersion="8" /></manifest>
public class DBOpenHandler extends SQLiteOpenHelper {/** * @param context 当前应用上下文 */public DBOpenHandler(Context context) {super(context, "myAndroid.db", null, 2);}@Overridepublic void onCreate(SQLiteDatabase db) {String sql_createTable = "CREATE TABLE person (personid integer primary key autoincrement, name)";db.execSQL(sql_createTable);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {String sql = "ALTER TABLE person ADD phone";db.execSQL(sql);db.execSQL("ALTER TABLE person ADD amount integer");}}
3. TContentProvider
/** * 内容提供者 */public class PersonContentProvider extends ContentProvider {private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);private static final int PERSONS = 1;private static final int PERSON = 2;private DBOpenHandler dbOpenHandler;// 静态初始化 Uri 匹配模式static {// content://wjh.android.provider.personprovider/person : 表示对 person 表所有数据进行操作MATCHER.addURI("wjh.android.provider.personprovider", "person", PERSONS);// content://wjh.android.provider.personprovider/person/3 : 表示对 Perosn 表 Id 为 3 的单体记录进行操作MATCHER.addURI("wjh.android.provider.personprovider", "person/#", PERSON);}/** * 其它应用可以通过此方法对内容提供者删除数据 */public int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();int num = 0;switch (MATCHER.match(uri)) {case PERSONS :num = db.delete("person", selection, selectionArgs);break;case PERSON:long id = ContentUris.parseId(uri);String where ="personid=" + id;if(selection != null && !"".equals(selection)) {where = where + "and" + selection;}num = db.delete("person", where, selectionArgs);break;default :throw new IllegalArgumentException("Unkown Uri :" + uri);}return num;}/** * 获取内容提供者内容的类型 */@Overridepublic String getType(Uri uri) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS :// vnd.android.cursor.dir : 集合类型return "vnd.android.cursor.dir/person";case PERSON:// vnd.android.cursor.item : 单条记录return "vnd.android.cursor.item/person";default :throw new IllegalArgumentException("Unkown Uri :" + uri);}}/** * 其它应用可以通过此方法对内容提供者添加数据 */public Uri insert(Uri uri, ContentValues contentValues) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS :long rowid = db.insert("person", "name", contentValues);return ContentUris.withAppendedId(uri, rowid);default :throw new IllegalArgumentException("Unkown Uri :" + uri);}}public boolean onCreate() {dbOpenHandler = new DBOpenHandler(getContext());return true;}/** * 其它应用可以通过此方法对内容提供者查询数据 */public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS :return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);case PERSON:long id = ContentUris.parseId(uri);String where ="personid=" + id;if(selection != null && !"".equals(selection)) {where = where + "and" + selection;}return db.query("person", projection, where, selectionArgs, null, null, sortOrder);default :throw new IllegalArgumentException("Unkown Uri :" + uri);}}/** * 其它应用可以通过此方法对内容提供者更新数据 */public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();int num = 0;switch (MATCHER.match(uri)) {case PERSONS :num = db.update("person", values, selection, selectionArgs);break;case PERSON:long id = ContentUris.parseId(uri);String where ="personid=" + id;if(selection != null && !"".equals(selection)) {where = where + "and" + selection;}num = db.update("person", values, where, selectionArgs);break;default :throw new IllegalArgumentException("Unkown Uri :" + uri);}return num;}}
应用二:用于测试访问应用一的内容提供者
1, AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="wjh.android.other" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <uses-library android:name="android.test.runner" /> <activity android:name=".OtherActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="7" /><instrumentation android:name="android.test.InstrumentationTestRunner"android:targetPackage="wjh.android.other" android:label="Tests for My App" /></manifest>
2,TestContentProvider : 测试类,测试访问应用一的内容提供者
public class TestContentProvider extends AndroidTestCase {private static final String TAG = "TestContentProvider";/** * 添加 */public void testSave() throws Throwable {ContentResolver contentResolver = this.getContext().getContentResolver();String uriStr = "content://wjh.android.provider.personprovider/person";Uri uri = Uri.parse(uriStr);ContentValues values = new ContentValues();values.put("name", "XXX");values.put("phone", "135123456");values.put("amount", "22222222222");uri = contentResolver.insert(uri, values );Log.i(TAG, uri.toString());}/** * 更新 */public void testUpdate() throws Throwable {ContentResolver contentResolver = this.getContext().getContentResolver();String uriStr = "content://wjh.android.provider.personprovider/person/3";Uri uri = Uri.parse(uriStr);ContentValues values = new ContentValues();values.put("name", "XXX");values.put("phone", "135123456");values.put("amount", "4444444");contentResolver.update(uri, values, null, null);}/** * 查找 */public void testFind() throws Throwable {ContentResolver contentResolver = this.getContext().getContentResolver();String uriStr = "content://wjh.android.provider.personprovider/person";Uri uri = Uri.parse(uriStr);Cursor cursor = contentResolver.query(uri, null, null, null, "personid asc");// 打印在日志信息上while(cursor.moveToNext()) {int personId = cursor.getInt(cursor.getColumnIndex("name"));String name = cursor.getString(cursor.getColumnIndex("name"));String phone = cursor.getString(cursor.getColumnIndex("phone"));int amount = cursor.getInt(cursor.getColumnIndex("amount"));Log.i(TAG, "Person [amount=" + amount + ", id=" + personId + ", name=" + name+ ", phone=" + phone + "]");}}/** * 删除 */public void testDelete() throws Throwable {ContentResolver contentResolver = this.getContext().getContentResolver();String uriStr = "content://wjh.android.provider.personprovider/person/3";Uri uri = Uri.parse(uriStr);contentResolver.delete(uri, null, null);}}
8. 监听内容提供者的数据变化
1. 内容提供者在数据发送更新时,需要发出一条更新通知,来通知注册在此URI上的访问者。
getContext().getContentResolver().notifyChange(uri, null);
例:在上例中,为 insert、update、delete方法执行成功后,发出更新通知
public Uri insert(Uri uri, ContentValues contentValues) {SQLiteDatabase db = dbOpenHandler.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS :long rowid = db.insert("person", "name", contentValues);// 由内容提供者发出内容更新的通知。getContext().getContentResolver().notifyChange(uri, null);return ContentUris.withAppendedId(uri, rowid);default :throw new IllegalArgumentException("Unkown Uri :" + uri); }}
2. 访问者需要监听内容提供者的通知
需要调用 ContentResolver 的 registerContentObserver 方法来注册一个监听器
registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)
@param uri :监听哪个 uri
@param notifyForDescendents : true
@param ContentObserver : 使用哪个监听器来处理更新事务
示例:
public class OtherActivity extends Activity { private static final String TAG = "OtherActivity"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String uriStr = "content://wjh.android.provider.personprovider/person";Uri uri = Uri.parse(uriStr);// 注册对 content://wjh.android.provider.personprovider/person 内容更新的观察 getContentResolver().registerContentObserver(uri, true, new PersonContenObserver(new Handler())); } /** * 更新监察者。 */ private final class PersonContenObserver extends ContentObserver { public PersonContenObserver(Handler handler) {super(handler);}@Overridepublic void onChange(boolean selfChange) {ContentResolver contentResolver = getContentResolver();String uriStr = "content://wjh.android.provider.personprovider/person";Uri uri = Uri.parse(uriStr);Cursor cursor = contentResolver.query(uri, null, null, null, "personid asc");while(cursor.moveToNext()) {int personId = cursor.getInt(cursor.getColumnIndex("name"));String name = cursor.getString(cursor.getColumnIndex("name"));String phone = cursor.getString(cursor.getColumnIndex("phone"));int amount = cursor.getInt(cursor.getColumnIndex("amount"));// 将获取的数据通过日志信息打印出来 ,实际应用中,可以用于同步应用中的数据Log.i(TAG, "Person [amount=" + amount + ", id=" + personId + ", name=" + name+ ", phone=" + phone + "]");}super.onChange(selfChange);} }}
实际应用,“通讯录” 数据读取、添加联系人信息
** 查看通讯录数据库:
首先启动模拟器、再打开“File Explorer” 视图,
依次展开:data -- data -- com.android.providers.contacts(注意和 com.android.contacts 区分) -- databases,如图:
点击右上角的导出图标,如图:
将数据库文件导出到电脑磁盘上。
然后,你需要拥有一个能打开 SQLite 数据库的工具。例如我用的 SQLite Expert Personal。可以在网上搜索下载。
打开数据库后,就比较纠结了,需要观察表结构。如果确实看得比较纠结,干脆甩开,以免打击学习激情。
或者一狠心,自己写一个管理联系人的程序,弄个自己的通讯录数据库。
raw_contacts 表: 联系人 ID
data表 : 联系人的数据表。通过raw_contacts_id 与 raw_contacts 表联系。
存放的联系人信息如:手机号、姓名、Email 等。
联系人的每一项数据,都会在 data 表产生一条记录。例如,记录手机号的是单独一条记录,记录 Email 的是单独一条记录。并且都用 data1 字段来存放。
也就是说,联系人的所有重要信息,都以单独记录的方式,保存在这张表里的 data1字段。用 raw_contacts_id 来描述信息所属的联系人。用 mimitype_id 来描述 data1 字段存储的数据类型(是 Email 数据么?手机号数据么?座机数据么?)。
假如data1要存放的数据是 “由几个数据组合起来的” ,例如:姓名中的 FirstName 和 LastName。
那么就往后存到 data2、data3 里面。组合起来的完整姓名存放在 data1。
区分这条数据到底是短信数据、电话数据、Emai等,则是依靠 mimitype_id 字段来区分。
mimitype_id 其实是 mimitypes 的外键。观察此表得知:1 表示 email、6 表示姓名、5 表示电话号码。
data2:也用来说明 data1。例如,如果是此记录记录的数据是电话号码,那么若是住宅电话,此字段为1;手机号码为2;单位电话为3......
这些字段的意义很重要,建议读者花10分钟大致看一眼(强烈建议不要花太多时间去研究这个,意义不大),再结合后面的程序,相信会很容易理解。
既然知道了数据存放的方式了,知道它们的字段的名称了,表名也知道了。(当然,编程时我们尽量使用 Android 提供的常量。否则也许今天写的程序,用到了某某字段,睡一觉起来 Android 升完级,不认了。)
好了,sql 语句的几个要素都成立了。要存取联系人好了做吧。
当然啦,这个过程要通过 “联系人” 对外提供的接口来完成,毕竟这个程序是人家的,这个表也是人家的,我们不能直接访问第三方程序的数据库。要提供这个接口的方式可多了,ContentProvider 无疑是最佳的选择。
说穿了,其实就是我们在我们的程序中,组拼出我们需要的 sql 语句,通过 ContentProvider 通信机制,将 sql 语句送到 “联系人”程序去执行而已。并不神奇和复杂,不是么?
calls表:存放的呼叫记录。在《Android--删除某联系人的通话记录》中需要操作它
源码在:
${对应版本SDK源码目录}/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java
可以通过查看源码,获知 Uri
...
matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);
matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);
matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);
matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID);
matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);
...
要按照电话号码获取某一个联系人可以使用:
Uri uri = Uri.parse("content://com.android.contacts/data/phones/filter/151016899999");
** 示例代码:(上代码之前,最好的建议是:边看这个例子,边打开数据库和源码瞅瞅,对 ContentProvider 的理解会深入很多)
1. AndroidManifest.xml 加入权限
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
2.
package wjh.android.contact;import java.util.ArrayList;import android.content.ContentProviderOperation;import android.content.ContentProviderResult;import android.content.ContentResolver;import android.content.ContentUris;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.provider.ContactsContract;import android.provider.ContactsContract.RawContacts;import android.provider.ContactsContract.CommonDataKinds.Email;import android.provider.ContactsContract.CommonDataKinds.Phone;import android.provider.ContactsContract.CommonDataKinds.StructuredName;import android.provider.ContactsContract.Contacts.Data;import android.test.AndroidTestCase;import android.util.Log;/** * 通讯录操作示例 * */public class ContactTest extends AndroidTestCase {private static final String TAG = "ContactTest";/** * 获取通讯录中所有的联系人 */public void testGetContacts() throws Throwable {ContentResolver contentResolver = this.getContext().getContentResolver();String uriStr = "content://com.android.contacts/contacts";Uri uri = Uri.parse(uriStr);Cursor cursor = contentResolver.query(uri, null, null, null, null);// 遍历联系人while (cursor.moveToNext()) {// 联系人 IDint contactId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));// 联系人显示名称String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));// 联系人电话号码需要对另一个表进行查询,所以用到另一个 uri:content://com.android.contacts/data/phones Cursor phones = getContext().getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " // 根据上一步获取的联系人 id 来查询 + contactId, null, null); String phone = "";while (phones.moveToNext()) { // "data1"字段,所以此处也可以直接写 "data1",但不推荐phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));}// 再查询 Email。uri 为 : content://com.android.contacts/data/emails Cursor emails = getContext().getContentResolver().query( ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + contactId, null, null);while (emails.moveToNext()) { /* 一样是 "data1" 字段。现在明白了吧?一个联系人的信息,其实被分成了好几条记录来保存,data1分别保存了各种重要的信息。 * 是时候参照打开数据库我前面所说,去瞄一眼它的表结构了! */String emailAddress = emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));Log.i("RongActivity", "emailAddress=" + emailAddress);}emails.close();Log.i(TAG, "Contact [contactId= "+ contactId +"name=" + name + ", phone=" + phone + "]");}}/** * 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId * 这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见 */public void testInsert() {ContentValues values = new ContentValues();//首先向RawContacts.CONTENT_URI执行一个空值插入(raw_contacts 表), 为了获取生成的联系人 IDUri rawContactUri = this.getContext().getContentResolver().insert(RawContacts.CONTENT_URI, values);//然后获取系统返回的rawContactId , 就是新加入的这个联系人的 IDlong rawContactId = ContentUris.parseId(rawContactUri); /* Andorid 中,将联系人的姓名、电话、Email * 分别存放在 data 表的同一个字段的三条记录当中 * 因此要 Insert 三次 *///往data表入姓名数据values.clear();// raw_contacts_id 字段,是 raw_contacts表id 的外键,用于说明此记录属于哪一个联系人values.put(Data.RAW_CONTACT_ID, rawContactId); // mimitype_id 字段,用于描述此数据的类型,电话号码?Email?....values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); // 注意查看第二个参数的常量值values.put(StructuredName.GIVEN_NAME, "文白菜"); // 这个名字真好听this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);//往data表入电话数据values.clear();values.put(Data.RAW_CONTACT_ID, rawContactId);values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); values.put(Phone.NUMBER, "15101689230");values.put(Phone.TYPE, Phone.TYPE_MOBILE);this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);//往data表入Email数据values.clear();values.put(Data.RAW_CONTACT_ID, rawContactId);values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);values.put(Email.DATA, "wenlin56@sina.com");values.put(Email.TYPE, Email.TYPE_WORK);this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);}/** * 在同一个事务当中保存联系人 */public void testSave() throws Throwable{//文档位置:reference/android/provider/ContactsContract.RawContacts.htmlArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();int rawContactInsertIndex = ops.size();ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) .withValue(RawContacts.ACCOUNT_TYPE, null) .withValue(RawContacts.ACCOUNT_NAME, null) .build());//文档位置:reference/android/provider/ContactsContract.Data.htmlops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI) .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex) .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) .withValue(StructuredName.GIVEN_NAME, "文萝卜") .build());// 更新手机号码:Data.RAW_CONTACT_ID 获取上一条语句插入联系人时产生的 IDops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI) .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex) .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE) .withValue(Phone.NUMBER, "15101689231") // "data1" .withValue(Phone.TYPE, Phone.TYPE_MOBILE) .withValue(Phone.LABEL, "手机号") .build());ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI) .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex) .withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE) .withValue(Email.DATA, "wenlin56@yahoo.cn") .withValue(Email.TYPE, Email.TYPE_WORK) .build());// 批量插入 -- 在同一个事务当中ContentProviderResult[] results = this.getContext().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);for(ContentProviderResult result : results){Log.i(TAG, result.uri.toString());}}}
- }
- 使用 ContentProvider 共享数据 访问与添加通讯录
- Android深入探究笔记之十 -- 使用 ContentProvider 共享数据(二),访问与添加通讯录
- Android深入探究笔记之十 -- 使用 ContentProvider 共享数据(二),访问与添加通讯录
- 使用ContentResolver访问通讯录ContentProvider
- 使用ContentResolver访问通讯录ContentProvider
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- 使用ContentProvider共享数据
- java类的生命周期
- webkit 源码分析系列--css样式解析
- Oracle数据库的三种标准的备份方法
- iphone之MKReverseGeocoder 地理位置反向编码
- tomcat占用jvm内存数修改方法及监控方法
- 使用 ContentProvider 共享数据 访问与添加通讯录
- Ubuntu建立(apache+php+mysql)+phpmyadmin
- HashMap和Hashtable的区别
- 腾讯这家公司的核心竞争力是什么?为什么?
- hibernate 一对多关联 (1)单向关联
- 计算几何常用算法
- scull0字符设备驱动示例(参考《Linux设备驱动程序》)
- Derby数据库
- VC 64位程序开发心的——获得程序位数和操作系统位数