Android學習筆記二十一.使用ContentProvider實現資料共用(四).作業系統(連絡人)的ContentProvider,androidprovider

來源:互聯網
上載者:User

Android學習筆記二十一.使用ContentProvider實現資料共用(四).作業系統(連絡人)的ContentProvider,androidprovider
    Android系統本身提供了大量的ContentProvider,例如連絡人資訊、系統的多媒體資訊等,我們開發的應用程式主要是通過ContentResolver來調用系統的ContentProvider提供的query()、insert()、update()和delete()方法來擷取Android內部的資料。一、如何使用ContentResolver作業系統ContentProvider暴露的內部資料?1.調用Activity的getContentResolver()擷取ContentResolver對象;2.根據需要調用ContentResolver的insert()、delete()、update()和query()方法操作資料。二、實戰源碼剖析1.加入讀寫權限<uses-permission android:name="android.permission.READ_CONTACTS" />     //授予讀連絡人ContentProvider的許可權<uses-permission android:name="android.permission.WRITE_CONTACTS" />   //授予寫連絡人ContentProvider的許可權2.連絡人ContentProvider的Uri(1)ContactsContract.Contacts.CONTENT_URI(content://com.android.contacts/contacts):管理連絡人的Uri;(2)ContactsContract.CommonDataKinds.Phone.CONTENT_URI(content://com.android.contacts/data/phones):管理連絡人的電話的Uri;(3)ContactsContract.CommonDataKinds.Email.CONTENT_URI(content://com.android.contacts/data/emails ):管理連絡人的E-Mail的Uri。3.取得所有連絡人的表的Cursor對象:
1)ContentResolver contentResolver=getContentResolver();//擷取 ContentResolver物件查詢在ContentProvider裡定義的共用對象;2)Cursor cursor=contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);//根據URI對象ContactsContract.Contacts.CONTENT_URI查詢所有連絡人4.擷取指定連絡人(_ID)的具體資訊    從Cursor對象裡我們關鍵是要取得連絡人的_id。通過它,再通過ContactsContract.CommonDataKinds的各個子類查詢該_id連絡人的電話(ContactsContract.CommonDataKinds.Phone),email(ContactsContract.CommonDataKinds.Email)等等。以取得該連絡人所有電話為例:1)int idFieldIndex=cursor.getColumnIndex(ContactsContract.Contacts._ID);      int id=cursor.getInt(idFieldIndex);//根據列名取得該連絡人的id;2)Cursor phonecursor=contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+id, null, null);//再類ContactsContract.CommonDataKinds.Phone中根據查詢相應id連絡人的所有電話;    類似地可以ContactsContract.CommonDataKinds的不同的子類查詢不同的內容。android文檔告訴我們推薦使用ContactsContract.Contacts.LOOKUP_KEY代替ContactsContract.Contacts._ID。

升華筆記:1.Cursor介面(1)功能概述:該介面主要用於隨機讀寫從資料庫查詢返回的set集合形式的結果。(2)常用方法:abstract void close() :關閉Cursor,釋放所有資源abstract boolean moveToNext() :將遊標移動到下一行String getString(int columnIndex):將指定的列索引對應的值轉換為字串返回int getColumnIndex(String columnName) :返回給定列名對應的列索引值(為0開始的整型值),傳入參數為列名;2.由於讀取連絡人比較的佔用資源,為了提高使用者的體驗度。考慮將讀取的過程放線上程裡完成,推薦使用AsyncTask類。取Android系統的通訊錄時一般會先讀取連絡人然後再讀取其號碼,嵌套迴圈讀取。如果通訊錄人數不多速度尚可,但是通訊錄裡有1-2百人恐怕就比較慢了,如果硬體再差點體驗就更差了。可以使用ContactsContract.CommonDataKinds.Phone.CONTENT_URI(對應contacts2.db的資料檢視view_data_restricted)視圖來讀取避免嵌套讀取,而對於PhoneLookup.CONTENT_FILTER_URI確不能直接使用 4.連絡人的API(1)ContactsContract[public final class]    java.lang.Object                   ↳ android.provider.ContactsContract    ContactsContract是連絡人資料提供者和應用程式的契約書,它定義所有支援的Content Provider URI和資料列。 從Android 2.0(API Level 5)開始,Android平台提供了一個改進的Contacts API,以適應一個連絡人可以有多個帳戶的需求,比如說手機通訊錄和GMAIL通訊錄,兩個通訊錄中的兩條記錄可以是同一個人。新的Contacts API主要是由ContactsContract及其相關的類來管理,舊的API(android.provider.Contacts)已不贊成使用,但為了相容仍可以使用,只不過像以前一樣,只能返回第一個帳戶的資訊。   在新的Contacts API中,連絡人資料被放到三張表中:Contacts、RawContacts和Data。這樣可以協助系統更好地儲存與管理一個連絡人的多個帳戶的資訊。ContactsContract表結構介紹:A.ContactsContract.Data 用於儲存個人資料,例如電話號碼、郵件、手機鈴聲、即時通訊方式、照片等等B.ContactsContract.RawContacts 用於關聯連絡人資訊與帳號,因為有可能手機的連絡人資訊是從不同的Gmail或者其他地方匯入的,為互相區別並方便同步,特引入帳號概念。C.ContactsContract.Contacts 屬於不同帳號下的某連絡人資訊可能描述的是同一個人,這張表就是RawContacts的並集,如果某連絡人資訊被修改,和它描述同一個人資訊肯定也要做相應的更新。
(2)ContactsContract.Data    Data表格儲存體了連絡人的詳細資料,表中的每一行儲存一個特定類型的資訊,比如Email、Address或Phone。每一行通過一個mimetype_id的欄位來表示該行儲存的是什麼類型的資料,該欄位引用了mimetyps表,此表格儲存體了常用的資料類型。Data表的欄位主要有:mimetype_id :表示該行儲存的資訊的類型 raw_contact_id: 表示該行所屬的RawContactis_primary :多個data資料群組成一個raw contact,該欄位表示此data是否是其所屬的raw contact的主data,即其display name會作為raw contact的display nameis_super_primary :該data是否是其所屬的contact的主data,如果is_super_primary為1則is_primary一定為1data1~data15 :15個資料欄位,對於不同類型的資訊,表示不同的含義,ContactsContract.CommomDataKinds類中定義了與常用的資料類型相對應的一些類,這些類中分別定義了相應資料類型中這些欄位表示的含義。一般data1表是主資訊(如電話,Email地址等),data2表示副資訊,data15表示Blob資料。data_sync1~data_sync4 sync_adapter:要用的欄位(sync_adapter用於資料的同步,比如你手機中的Gmail帳戶與Google伺服器的同步)。data_version :資料的版本,用於資料的同步。    Data類中的Data.CONTACT_ID與Data.RAW_CONTACT_ID分別表示該表項對應的連絡人在Contact與RawContract表中的ID,我們只需要知道某一個連絡人的contactId或rawContractId,並根據其尋找的資料的類型就可以查到相應類型的資訊。(3)ContactsContract.RawContact    RawContact表中的一行儲存Data表中一些資料行的集合及一些其他的資訊,表示一個連絡人某一特定帳戶的資訊,比如Facebook或Exchange的一個連絡人。 當插入一個raw contact或當一個raw contact所屬的一個data改變時,系統會檢查這個raw contact跟其他的raw contact是否可以匹配(比如如果兩個raw contact的data包含相同的電話號碼或名字),如果匹配他們就會被綜合到一起,也就是說他們會屬於同一個cantact,表現為在RawContact表中他們引用的cantact_id是一樣的。 連絡人姓名、組織、電話號碼、Email或暱稱的改變會引發raw contact的重新彙總。有兩個方法控制彙總的行為Aggregaton Mode與ContactsContract.AggregationExceptions。 Aggregaton Mode:RawContact表中有一個欄位aggregation_mode,通過向特定raw contact行中插入這個欄位可以修改系統對這個raw contact的彙總行為,其允許的值如下:AGGREGATION_MODE_DEFAULT:正常模式,允許自動彙總;AGGREGATION_MODE_DISABLE:不允許彙總;AGGREGATION_MODE_SUSPENDED:當一個raw contact的aggregation mode修改為suspended時,如果其已是一個已彙總的contact的一部分,那麼它仍會保持與原來彙總到一起的raw contact的關係,即使它已改變不再跟其他raw contact匹配。ContactsContract.AggregationExceptions:在資料庫中存在一個表:agg_exceptions。通過欄位raw_contact_id1、raw_contact_id2、mode儲存兩個raw contact彙總的方法,系統定義的彙總行為有3個:TYPE_AUTOMATIC=0  由系統決定彙總行為,預設值。TYPE_KEEP_SEPARATE=2  不彙總TYPE_KEEP_TOGETHER=1  彙總(4)ContactsContract.ContactContact表中的一行表示一個連絡人,它是RawContact表中的一行或多行的資料的組合,這些RawContact表中的行表示同一個人的不同的帳戶資訊。Contact中的資料由系統組合RawContact表中的資料自動產生。 不可以直接向這個表中插入資料,當一個raw contact被插入的時候,系統會首先尋找Contact表看是否有記錄跟插入的raw contact表示同一個人,如果找到了,則把找到的這個contact的_ID插入raw contact記錄的CONTACT_ID欄位,如果沒有找到,則系統自動插入一個Contact記錄並把它的_ID插入新插入的raw contact的CONTACT_ID列。 Contact表中只有TIMES_CONTACTED、LAST_TIME_CONTACTED、STARRED、CUSTOM_RINGTONE、SENE_TO_VOICEMAIL列可更改,這些列的更改會導致相應的raw contact被更改。 當刪除Contact表中的記錄時,會刪除一個連絡人的所有帳戶的資訊,也就是說,其對應的所有raw contacts也會被刪除,各raw contact對應的data也就被刪除了,sync adapter同步時也會刪除伺服器端的相應記錄。 如果需要讀取一個連絡人的資訊用CONTENT_LOOKUP_RUI代替CONTENT_URI(見後面);如果需要通過電話號碼尋找一個連絡人,用PhoneLookup.CONTENT_FIILTER_URI,這個URI為這個目的進行了最佳化;如果需要通過部分名字的匹配尋找,用CONTENT_FILTER_URI;如果需要通過email,address等資訊尋找,尋找表ContactsContract.Data,結果包含contact ID,名字...    ContactsContract的子類ContactsContract.Contacts是一張表,代表了所有連絡人的統計資訊。比如連絡人ID(—ID),查詢鍵(LOOKUP_KEY),連絡人的姓名(DISPLAY_NAME_PRIMARY),頭像的id(PHOTO_ID)以及群組的id等等。
(5)ContactsContract.CommonDataKinds類在前面講Data表的結構時講到,Data的data1~data15欄位用於儲存各類型的資料資訊,那麼這15個欄位分別表示什麼資訊呢?前面提到了,Data表中有一個mimetype_id欄位,通過這個欄位關聯mimetypes表表示該行代表的資訊類型,因為Data表中的每一行可以表示如Phone或Address等不同類型的資訊,所以對於不同類型的資訊,data1~data15這15列表示不同的含義,如果要靠記憶記住這15列對於特定的類型分別表示什麼意義自然不行,於是Google就預定義了一些類,每一個類對應一些預先定義好的資料類型,在每個類中定義了一些語義地、方便記憶的常量,用來對應這15個欄位,比如在CommonDataKinds.Email類中有如下定義publicstaticfinal String ADDRESS = DATA1;publicstaticfinal String DISPLAY_NAME = DATA4;DATA1與DATA4為繼承自DataColumns中的常量,在DataColumns中是這樣定義的:publicstaticfinal String DATA1 = "data1";publicstaticfinal String DATA4 = "data4";這樣,當於們要尋找Email地址時,只需要通過ContactsContract.CommonDataKinds.Email.ADDRESS引用,而不需要知道它是儲存在Data表中的data1列中。 三、源碼
public class ContactProviderTest extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.main);  Button search=(Button)findViewById(R.id.searchBtn);  /*查詢連絡人*/  search.setOnClickListener(new OnClickListener(){   @Override   public void onClick(View v) {   //1.定義兩個List來封裝系統的連絡人資訊,指定連絡人的電話號碼、Email等詳情    final ArrayList<String> names=new ArrayList<String>();    final ArrayList<ArrayList<String>> details=new ArrayList<ArrayList<String>>();   //2.使用ContentResolver尋找連絡人資料(Query the given URI, returning a Cursor over the result set)    Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);   //3.遍曆查詢結果,擷取系統中所有連絡人    while(cursor.moveToNext())    {     //a.擷取連絡人ID     String contactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));     //b.擷取連絡人的名字     String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));     names.add(name); //將名字依次添加到List列表中          /*-----------------------------------------------------------------------------------------------------*/          //c.使用ContentResolver尋找連絡人的電話號碼     Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,                 null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);     //d.遍曆查詢結果,擷取該連絡人的多個電話號碼     ArrayList<String> detail = new ArrayList<String>();     while(phones.moveToNext())     {      String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));      detail.add("電話號碼"+phoneNumber);     }     phones.close();          /*-----------------------------------------------------------------------------------------------------*/          //e.使用ContentResolver尋找連絡人的E-Mail地址     Cursor emails = getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,       ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+contactId, null, null);     //f.遍曆查詢結果,擷取該連絡人的多個E-Mail地址     while(emails.moveToNext())     {      String emailAddress = emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));      detail.add("郵件地址:"+emailAddress);     }     emails.close();     details.add(detail);    }    cursor.close();       /*-----------------------------------------------------------------------------------------------------*/      //4.載入result.xml    View resultDialog = getLayoutInflater().inflate(R.layout.result, null);   //5.擷取resultDialog中ID為list的ExpandableListView    ExpandableListView list = (ExpandableListView) resultDialog.findViewById(R.id.list);   //6.建立一個ExpandableListAdapter對象    ExpandableListAdapter adapter = new BaseExpandableListAdapter()    {     //a.擷取指定組位置、指定子清單項目處的子清單項目資料          @Override     public Object getChild(int groupPosition, int childPosition) {           return details.get(groupPosition).get(childPosition);     }     @Override     public long getChildId(int groupPosition, int childPosition) {           return childPosition;     }     @Override     public int getChildrenCount(int groupPosition) {           return details.get(groupPosition).size();     }     private TextView getTextView()     {      AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 64);      TextView textView = new TextView(ContactProviderTest.this);      textView.setLayoutParams(lp);      textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);      textView.setPadding(36, 0, 0, 0);      textView.setTextSize(20);      return textView;          }              //b.該方法決定每個子選項的外觀     @Override     public View getChildView(int groupPosition,       int childPosition, boolean isLastChild,       View convertView, ViewGroup parent)     {      TextView textView = getTextView();      textView.setText(getChild(groupPosition,childPosition).toString());      return textView;     }     //c.擷取指定組位置處的組資料     @Override     public Object getGroup(int groupPosition) {      return names.get(groupPosition);     }     @Override     public int getGroupCount() {      return names.size();     }     @Override     public long getGroupId(int groupPosition) {      return groupPosition;     }        //d.該方法決定每個組選項的外觀     @Override     public View getGroupView(int groupPosition,       boolean isExpanded, View convertView,       ViewGroup parent) {      TextView textView = getTextView();      textView.setText(getGroup(groupPosition).toString());      return textView;     }     @Override     public boolean isChildSelectable(int groupPosition,       int childPosition) {      return true;     }     @Override     public boolean hasStableIds() {      return true;     }    };    //7.為ExpandableListView設定Adapter對象    list.setAdapter(adapter);    //8.使用對話方塊來顯示查詢結果    new AlertDialog.Builder(ContactProviderTest.this)       .setView(resultDialog)       .setPositiveButton("確定",null)       .show();   }     });  /*新增連絡人...*/  Button add=(Button)findViewById(R.id.addBtn);  add.setOnClickListener(new OnClickListener(){   @Override   public void onClick(View v) {    //a.擷取程式介面中的三個文字框    String name = ((EditText)findViewById(R.id.name)).getText().toString();    String phone = ((EditText)findViewById(R.id.phone)).getText().toString();    String email = ((EditText)findViewById(R.id.email)).getText().toString();    //b.建立一個空的ContentValues    ContentValues values = new ContentValues();    //c.向RawContacts.CONTENT_URI執行一個空值插入嗎,目的是擷取系統返回的rawContactId    Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);    long rawContactId=ContentUris.parseId(rawContactUri);    values.clear();       /*-----------------------------------------------------*/       values.put(Data.RAW_CONTACT_ID, rawContactId);    //d.設定內容類型    values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);    //e.設定連絡人名字    values.put(StructuredName.GIVEN_NAME, name);    //f.向連絡人URI新增連絡人...名字    getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);    values.clear();       /*-----------------------------------------------------*/       values.put(Data.RAW_CONTACT_ID, rawContactId);    values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);    //g.設定連絡人的電話號碼    values.put(Phone.NUMBER, phone);    //h.設定電話類型    values.put(Phone.TYPE, Phone.TYPE_MOBILE);    //i.向連絡人電話號碼URI添加電話號碼    getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);    values.clear();       /*-----------------------------------------------------*/       values.put(Data.RAW_CONTACT_ID, rawContactId);    values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);    //j.設定連絡人的E-mail地址    values.put(Email.DATA, email);    //k.設定該電子郵件的類型    values.put(Email.TYPE, Email.TYPE_WORK);    //l.向連絡人E-mail URI添加E-mail資料    getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);       Toast.makeText(ContactProviderTest.this,"連絡人資料添加成功", Toast.LENGTH_SHORT).show();   }     }); } }

效果如下:
參考:http://blog.163.com/hesky_fly/blog/static/732868692011102311551131/http://wear.techbrood.com/reference/android/provider/ContactsContract.Data.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.