轉:http://lichangsong.blog.51cto.com/7997447/1306033
最近兩天在做通訊錄的增刪改查功能。原以爲Android會將通訊錄的所有數據都集合到一個數據庫表中,然後知道其ContentProvider提供Uri後,通過ContentResolver的query(),insert(),update(),delete()方法直接操作數據庫的數據,今天把其所有功能實現後,才發現並非自己當初想象的那麼簡單,好了,廢話不多說。
一.權限
操作通訊錄必須在AndroidManifest.xml中先添加2個權限,
1
2
|
< uses-permission android:name = "android.permission.READ_CONTACTS" /> < uses-permission android:name = "android.permission.WRITE_CONTACTS" /> |
二.通訊錄數據庫表介紹 (重點)
1.minetypes表
2.data表
3.raw_contacts表
注意: 3表第二個圖是接第一圖的右邊的,因爲大小的原因,截成了2張圖。
首先說一下,聯繫人的信息操作前,必須把數據庫的這3個表仔細看一下,看不懂也沒關係,等會對進行增刪改查的操作的時候,再回來對照數據庫,這樣你能夠更加方便理解和記憶代碼。否則,死記代碼,過兩天就忘的一乾二淨。
通訊錄是存放在/data/data/com.android.providers.contacts/databases/contacts2.db,裏面主要的表有:
(1)raw_contacts:存放聯繫人的 ID,_id屬性爲主鍵,聲明爲autoincrement,即不需要手動設置,其他屬性也不需要手動設置就有默認值;display_name屬性爲姓名;sort_key屬性可以用於查詢後的排序
(2)mimetypes:存放數據的類型,比如"vnd.android.cursor.item/name"表示“姓名”類型的數據,"vnd.android.cursor.item/phone_v2"表示“電話”類型的數據;
(3)data:存放具體的數據;raw_contact_id 屬性用來連接raw_contacts表,每條記錄表示一個具體數據;raw_contact_id 需要重點記住,手機中顯示的每一個聯繫人對應一個固定的raw_contact_id,raw_contact_id 對應着 raw_contacts表的 _id ,他倆是相同的值,兩個表之間的關係必須理清。(我剛開始就是沒有理清表之間的關係,以及各個字段代表的意思,做起來就感覺很混亂,這3個表很重要)我們主要的數據(email、phone等)都存放在data表;
data1屬性存放總數據;
data2屬性:
-如果此記錄存放姓名,則data2存放名;
-如果此記錄存放電話,則data2存放類型,比如手機、家電;
-如果此記錄存放組織,則data2存放類型,比如公司、其他;
-如果此記錄存放地址,則data2存放類型,比如住宅,單位等
三.重要數據
URI
對raw_contacts表添加、刪除、更新操作:
URI =content://com.android.contacts/raw_contacts;
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
URI =content://com.android.contacts/data/emails/filter/*
URI =content://com.android.contacts/data/phone/filter/*
然後where條件爲:raw_contact_id=? and mimetype = ?
MIMETYPE
Data中的常量
Data._ID: "_id"
Data.DISPLAY_NAME:“display_name”
Data.DATA1:“data1”
Data.DATA2:“data2”
Data.RAW_CONTACT_ID:“raw_contact_id”
Data.MIMETYPE:“mimetype”
四.增刪改查的實現
1.query
(1)查詢所有的聯繫人
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
//讀取通訊錄的全部的聯繫人
//需要先在raw_contact表中遍歷id,並根據id到data表中獲取數據 public
void testReadAll(){ //uri = content://com.android.contacts/contacts Uri uri = Uri.parse( "content://com.android.contacts/contacts" ); //訪問raw_contacts表 ContentResolver resolver = this .getContext().getContentResolver(); //獲得_id屬性 Cursor cursor = resolver.query(uri, new
String []{Data._ID}, null ,
null , null );
while (cursor.moveToNext()){ StringBuilder buf = new
StringBuilder(); //獲得id並且在data中尋找數據 int id = cursor.getInt( 0 ); buf.append( "id=" +id); uri = Uri.parse( "content://com.android.contacts/contacts/" +id+ "/data" ); //data1存儲各個記錄的總數據,mimetype存放記錄的類型,如電話、email等 Cursor cursor2 = resolver.query(uri, new
String []{Data.DATA1,Data.MIMETYPE}, null , null , null );
while (cursor2.moveToNext()){ String data = cursor2.getString(cursor2.getColumnIndex( "data1" )); if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/name" )){ //如果是名字
buf.append( ",name=" +data); } else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/phone_v2" )){ //如果是電話
buf.append( ",phone=" +data); } else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/email_v2" )){ //如果是email
buf.append( ",email=" +data); } else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/postal-address_v2" )){ //如果是地址
buf.append( ",address=" +data); } else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/organization" )){ //如果是組織
buf.append( ",organization=" +data); } } String str = buf.toString();
Log.i( "Contacts" , str); } } |
(2)根據電話號碼查詢姓名
1
2
3
4
5
6
7
8
9
10
11
12
|
//根據電話號碼查詢姓名(在一個電話打過來時,如果此電話在通訊錄中,則顯示姓名) public void
testReadNameByPhone(){ String phone = "12345678" ;
//uri= content://com.android.contacts/data/phones/filter/# Uri uri = Uri.parse( "content://com.android.contacts/data/phones/filter/" +phone); ContentResolver resolver = this .getContext().getContentResolver(); Cursor cursor = resolver.query(uri, new
String[]{Data.DISPLAY_NAME}, null ,
null , null );
//從raw_contact表中返回display_name if (cursor.moveToFirst()){ Log.i( "Contacts" , "name=" +cursor.getString( 0 )); } } |
2.Insert
注意:對某個聯繫人插入姓名、電話等記錄時必須要插入Data.MIMETYPE(或者是"mimetype")屬性,而不是插入"mimetype_id"!
比如:values.put(Data.MIMETYPE,"vnd.android.cursor.item/phone_v2")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
//一步一步添加數據
public void
testAddContacts(){ //插入raw_contacts表,並獲取_id屬性 Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" ); ContentResolver resolver = this .getContext().getContentResolver(); ContentValues values = new
ContentValues(); long contact_id = ContentUris.parseId(resolver.insert(uri, values)); //插入data表 uri = Uri.parse( "content://com.android.contacts/data" ); //add Name values.put( "raw_contact_id" , contact_id); values.put(Data.MIMETYPE, "vnd.android.cursor.item/name" ); values.put( "data2" , "zdong" );
values.put( "data1" , "xzdong" );
resolver.insert(uri, values); values.clear(); //add Phone values.put( "raw_contact_id" , contact_id); values.put(Data.MIMETYPE, "vnd.android.cursor.item/phone_v2" ); values.put( "data2" , "2" );
//手機 values.put( "data1" , "87654321" );
resolver.insert(uri, values); values.clear(); //add email values.put( "raw_contact_id" , contact_id); values.put(Data.MIMETYPE, "vnd.android.cursor.item/email_v2" ); values.put( "data2" , "2" );
//單位 resolver.insert(uri, values); } |
批量添加數據
核心代碼:
(1)ContentProviderOperation operation = ContentProviderOperation.newInsert(uri).withValue("key","value").build();
(2)resolver.applyBatch("authorities",operations);//批量提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public
void testAddContactsInTransaction() throws Exception {
Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" ); ContentResolver resolver = this .getContext().getContentResolver(); ArrayList<ContentProviderOperation> operations = new
ArrayList<ContentProviderOperation>(); // 向raw_contact表添加一條記錄 //此處.withValue("account_name", null)一定要加,不然會拋NullPointerException ContentProviderOperation operation1 = ContentProviderOperation .newInsert(uri).withValue( "account_name" , null ).build();
operations.add(operation1); // 向data添加數據 uri = Uri.parse( "content://com.android.contacts/data" ); //添加姓名 ContentProviderOperation operation2 = ContentProviderOperation .newInsert(uri).withValueBackReference( "raw_contact_id" , 0 )
//withValueBackReference的第二個參數表示引用operations[0]的操作的返回id作爲此值 .withValue( "mimetype" , "vnd.android.cursor.item/name" ) .withValue( "data2" , "xzdong" ).build(); operations.add(operation2); //添加手機數據 ContentProviderOperation operation3 = ContentProviderOperation .newInsert(uri).withValueBackReference( "raw_contact_id" , 0 )
.withValue( "mimetype" , "vnd.android.cursor.item/phone_v2" ) .withValue( "data2" , "2" ).withValue( "data1" , "0000000" ).build(); operations.add(operation3); resolver.applyBatch( "com.android.contacts" , operations); |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
void testDelete() throws Exception{
String name = "xzdong" ;
//根據姓名求id Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" ); ContentResolver resolver = this .getContext().getContentResolver(); Cursor cursor = resolver.query(uri, new
String[]{Data._ID}, "display_name=?" , new
String[]{name}, null );
if (cursor.moveToFirst()){ int id = cursor.getInt( 0 ); //根據id刪除data中的相應數據 resolver.delete(uri, "display_name=?" , new
String[]{name}); uri = Uri.parse( "content://com.android.contacts/data" ); resolver.delete(uri, "raw_contact_id=?" , new
String[]{id+ "" }); } } |
核心思想:
(1)不需要更新raw_contacts,只需要更新data表;
(2)uri=content://com.android.contacts/data 表示對data表進行操作;
1
2
3
4
5
6
7
8
9
|
public
void testUpdate() throws Exception{
int id =
1 ; String phone = "999999" ;
Uri uri = Uri.parse( "content://com.android.contacts/data" );//對data表的所有數據操作 ContentResolver resolver = this .getContext().getContentResolver(); ContentValues values = new
ContentValues(); values.put( "data1" , phone); resolver.update(uri, values, "mimetype=? and raw_contact_id=?" , new
String[]{ "vnd.android.cursor.item/phone_v2" ,id+ "" }) } |