1. 程式人生 > >Android學習筆記(四七):Content Provider初談和Android聯絡人資訊

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。