Android學習筆記(四七):Content Provider初談和Android聯絡人資訊
Content Provider
在資料處理中,Android通常使用Content Provider的方式。Content Provider使用Uri例項作為控制代碼的資料封裝的,很方便地訪問地進行資料的增、刪、改、查的操作。Android並不提供所有應用共享的資料儲存,採用content Provider,提供簡單便捷的介面來保持和獲取資料,也可以實現跨應用的資料訪問。簡單地說,Android通過content Provider從資料的封裝中獲取資訊。
Content provider使用Uri的方式來定位資訊。以“content://”開頭來表明這是一個content URI。例如“content://contstans/5”,其中“content://constans”稱為base URI,相當於資料的namespace,它的結構可以更為複雜,可以有多層結構。例子中的“5”,則是具體例項的標識。
一般來講,Android的資料儲存有4種方式:
1、 Preferences,參見Preference的使用,通常都是鍵值對(name-value pair)。
2、檔案:在手機裝置或者外設上儲存,預設的只能由建立的應用訪問。
3、資料庫(RDBMS):SQLite方式,參見SQLite的使用,由建立的應用訪問。
4、網路:Android提供API遠端在伺服器上儲存資料。
如果我們需要在應用中共享,採用Content Provider。無論資料具體的儲存方式,Content Provider提供了一個統一的介面。資料將採用類表格的方式提供,有行有列,列表示不同屬性的資料,例如電話號碼、電郵地址等。每個記錄(每行)都有一個唯一的_ID欄位來標識
原生providers
Android提供一些原生的content provider,來往問系統中的視訊、影象和聯絡人資訊等等。例如聯絡人的URI為“content://com.android.contacts/contacts”,原生的providers一般都有定義,例如聯絡人為ContactsContract.Contacts.CONTENT_URI。由於系統不同版本可能會存在差異,我們應儘可能使用系統的定義。
在android.provider的包中,可以檢視原生的provider,例如有AlarmClock、Browser、CalendarContract、CallLog、ContactsContract(包括有Contacts,Groups,PhoneLookup等)、MediaStore(Audio 『Albums、Artists、Genres、Playlists』、Files、Images、Video)和Setting。
通過Content Providers讀取資訊
我們利用原生provider聯絡人來看看如何來讀取資訊,聯絡人的資料結構比較複雜,後面會詳細介紹,這裡我們將盡可能簡化,先對Content Provider有個直觀的認識。核心是通過managedQuery( )來獲取Cursor。Cursor實際返回是一個二維的表格,有行有列,行是具體的元素,列是該元素具體的屬性。整個方式和SQLite非常相似。
public class Chapter26Test1 extendsListActivity {
private String[] INFO = new String[]{
ContactsContract.Contacts._ID,
//對於Content Provider返回資料表格而言,注意唯一標識_ID通常是必須讀取的,否則很容易報錯
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* managedQuery( )從Content Provider讀取資料
* 第1引數表示URI,
* 第2引數表示所需讀取的資訊,;
* 第3個引數是限制條件,類似SQL中的WHERE;
* 第4個引數和第3個引數配合使用,具體支援第三個引數中的“?”具體為何;
* 第5個引數類似於SQL中的ORDER BY */
Cursor contactCursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO, null,null,null);
ListAdapter adapter = new SimpleCursorAdapter(this,
R.layout.chapter_22_test1,contactCursor,
new String[]{ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts.HAS_PHONE_NUMBER},
new int[]{R.id.c22_name,R.id.c22_gravity});
setListAdapter(adapter); //偷偷懶,本例子直接利用了Android學習筆記(四十二)中SQLite例子中的xml
}
}
說說Android聯絡人資訊的組織結構及讀取
這是Android給出的聯絡人組織結構圖。分為三層。
第一層,Contact,即ContactContract.Contacts,是整合的聯絡人資訊。
第二層,RawConact,即ContactContract.RawContact,記錄的是該聯絡人來自某資訊源的資訊,例如本地輸入的,來自Google的,從微軟Exchange中匯出的,或則來自某個社交網站的資訊。每個RawContact記錄的資訊都來自同一資訊源。
第三層,Data,即ContactContract.Data,是具體的資訊儲存,例如記錄聯絡人姓名,email資訊,家庭電話,手機電話資訊等等,每一個Data都存放一個具體的資訊。在Data中的MIME TYPE說明儲存資訊的型別。具體在ContactContract.CommonDataKinds中定義。每個Data中有DATA1-DATA15個欄位來儲存資訊,各欄位所代表的含義,也可以在CommonDataKinds中具體查到。
下面,我們一層一層地讀取聯絡人資訊,將更清晰地看到這個結構。要讀取詳細資訊,對於Content Privider,關鍵是Uri逐層定位,才能獲取資訊。為了清晰表述,我們將整個路徑寫出來。
第一層資訊,將返回聯絡人列表中的多個Contacts,Uri為ContactsContract.Contacts.CONTENT_URI
private String[] INFO_1= new String[]{
ContactsContract.Contacts._ID,//這是每個row,也就是每個聯絡人的唯一的ID標識
ContactsContract.Contacts.DISPLAY_NAME,
};
Cursor cursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO_1,null,null,null);
cursor是表格形式,每一個行表示一個聯絡人。要讀取哪些列,在第二個引數String[]中定義。可以選取那些列,在Android Reference中的ContactsContract.Contacts中的Column中可以查到。最關鍵的列資訊為_ID,它是行,也就是每個聯絡人的唯一標識。除此之外,每個聯絡人的資訊會根據旗下的RawContact進行整合,因此,我們可以查到聯絡的名字ContactsContract.Contacts.DISPLAY_NAME等。
利用Contacts._ID,我們可以檢索第二層的資訊。
第二層資訊,將返回某聯絡人的多個RawContacts
同樣,返回表格中的列,可以檢視ContactsContract.RawContacts中檢視。我們選取下面的資訊,此外,如果要檢視資訊的來源,例如來自com.google,可通過RawContacts.ACCOUNT_TYPE和RawContacts.ACCOUNT_NAME兩個列檢視。
private String[ ] INFO_2 = {
ContactsContract.RawContacts._ID, //這是RawContact的唯一標識
ContactsContract.RawContacts.CONTACT_ID, //這是該RawContact關聯的Contact._ID
};
通過查詢全部的RawContacts,通過條件檢索,要求聯絡人的ID為指定的某聯絡人。在下面的例子在managedQuery中給出了param3和param4的條件,注意引數3,如果我們有多個條件,可以用AND等邏輯符合進行表述。
Cursor cursor = managedQuery(ContactsContract.RawContacts.CONTENT_URI ,
INFO_2 ,
RawContacts.CONTACT_ID + "=?" ,
new String[]{String.valueOf(contactId)} ,
null);
通過RawContacts._ID,我們可以往下檢索RawContacts下面各Data的資訊內容。
第三層資訊:將返回某RawContact的各Data的資訊
可查詢各列的資訊見ContactsContract.Data的介紹。
private String INFO_3[] = {
ContactsContract.Data._ID, //這是Data資訊塊的唯一標識
ContactsContract.Data.CONTACT_ID, //關聯第一層資訊的CONTACT_ID
ContactsContract.Data.RAW_CONTACT_ID, //關聯第二層資訊的RAW_IDCONTACT_ID
ContactsContract.Data.MIMETYPE, //具體含義可查ContactsContract.CommonDataKinds
ContactsContract.Data.DATA1, //通常讀取DATA1就可以,在具體的ContactsContract.CommonDataKinds.Phone/Email等查到DATA1-DATA15的含義
ContactsContract.Data.DATA2,
… …
ContactsContract.Data.DATA15,
};
讀取的方式有兩種。
方式一:指定定具體的Uri:
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawId);
Uri dataUri = Uri.withAppendedPath(rawContactUri,ContactsContract.RawContacts.Data.CONTENT_DIRECTORY);
Cursor cursor = managedQuery( dataUri, INFO_3,null, null, null);
方式二:另一種是利用RawContacts_ID或者Contact_ID,通過Data.CONTENT_URI,具體方式類RawContacts的檢索。
Cursor cursor = managedQuery(ContactsContract.Data.CONTENT_URI ,
INFO_3 ,
ContactsContract.Data.RAW_CONTACT_ID + "=?" ,
new String[]{String.valueOf(rawId)} ,
null);
總結一下架構圖。實際上Android的聯絡人提供了多種URI的的查詢方式,具體參加Android的reference。