一、通訊錄應用介紹
通訊錄應用是Android內建的應用程式,我們看到此應用的時候,可能只認為這是一個應用,用資料庫儲存資料,但是實際上不是這樣的。
通訊錄是ContentProvider的應用,通訊錄由兩部分組成:
(1)com.android.providers.contacts的ContentProvider:真正儲存資料的ContentProvider
(2)com.android.contacts:運用ContentResolver擷取資料的圖形化使用者介面;
二、擷取ContactProvider的原始碼
Android原始碼: http://my.oschina.net/zhanglubing/blog/40623 用git擷取;
如果要擷取ContactProvider,則安裝git,並開啟git bash,輸入
git clone https://android.googlesource.com/platform/packages/providers/ContactsProvider.git 即可;
目錄結構如下:
為何要擷取ContactProvider的原始碼呢?
因為如果要訪問ContentProvider,必須要瞭解URI的設定(authority,path等);只有查看原始碼才能夠知道;
AndroidManifest.xml為資訊清單檔,列出了ContactProvider的authorities,以及要訪問通訊錄需要的許可權;
[html]
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
主要的通訊錄程式為ContactsProvider2.java,authorities為:contacts或com.android.contacts;
三、通訊錄資料庫結構介紹
表結構如下:
通訊錄是存放在/data/data/com.android.providers.contacts/databases/contacts2.db,裡面主要的表有:
(1)raw_contacts:存放連絡人的ID,
_id屬性為主鍵,聲明為autoincrement,即不需要手動設定,其他屬性也不需要手動設定就有預設值;
display_name屬性為姓名;
(2)mimetypes:存放資料的類型,比如"vnd.android.cursor.item/name"表示“姓名”類型的資料,"vnd.android.cursor.item/phone_v2"表示“電話”類型的資料;
(3)data:存放具體的資料;
raw_contact_id屬性用來串連raw_contacts表,每條記錄表示一個具體資料;我們主要的資料(email、phone等)都存放在data表;
data1屬性存放總資料;
data2屬性:
-如果此記錄存放姓名,則data2存放名;
-如果此記錄存放電話,則data2存放類型,比如手機、家電;
-如果此記錄存放組織,則data2存放類型,比如公司、其他;
-如果此記錄存放地址,則data2存放類型,比如住宅,單位等;
四、對通訊錄做增刪改查
簡單的說:對通訊錄操作就是對一個普通的ContentProvider操作;
1.Query
(1)根據電話號碼查詢姓名
[java]
//根據電話號碼查詢姓名(在一個電話打過來時,如果此電話在通訊錄中,則顯示姓名)
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)查詢所有的連絡人
[java]
//讀取通訊錄的全部的連絡人
//需要先在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();
Cursor cursor = resolver.query(uri, new String[]{Data._ID}, null, null, null); //獲得_id屬性
while(cursor.moveToNext()){
StringBuilder buf = new StringBuilder();
int id = cursor.getInt(0);//獲得id並且在data中尋找資料
buf.append("id="+id);
uri = Uri.parse("content://com.android.contacts/contacts/"+id+"/data"); //如果要獲得data表中某個id對應的資料,則URI為content://com.android.contacts/contacts/#/data
Cursor cursor2 = resolver.query(uri, new String[]{Data.DATA1,Data.MIMETYPE}, null,null, null); //data1儲存各個記錄的總資料,mimetype存放記錄的類型,如電話、email等
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.Insert
(1)一步一步添加資料
[java]
//一步一步添加資料
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"); //單位
values.put("data1", "www.2cto.com");
resolver.insert(uri, values);
}
作者:xiazdong
(2)大量新增資料
核心代碼:
(1)ContentProviderOperation operation = ContentProviderOperation.newInsert(uri).withValue("key","value").build();
(2)resolver.applyBatch("authorities",operations);//批量提交
[java]
<span style="font-size:18px;">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);
}</span>
3.Delete
核心思想:
(1)先在raw_contacts表根據姓名查出id;
(2)在data表中只要raw_contact_id匹配的都刪除;
[java]
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+""});
}
}
4.Update
核心思想:
(1)不需要更新raw_contacts,只需要更新data表;
(2)uri=content://com.android.contacts/data 表示對data表進行操作;
[java]
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+""})
}
作者:xiazdong