注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。
原文鏈接: http://developer.android.com/training/contacts-provider/retrieve-details.html
這節課將會展示如何獲取一個聯系人的詳細數據,比如電子郵件地址,電話號碼,等等。當用戶獲得一個聯系人后,他會想要查看他的詳細信息。你可以展示給他們所有的信息,或者只展示某一特定類型的信息,比如電子郵件地址。
這節課中,我們假設你已經有了用戶選擇的一行 ContactsContract.Contacts 聯系人數據。在上一節課中(博客鏈接: http://www.cnblogs.com/jdneo/p/3674830.html )我們已經講解了如何獲取聯系人列表的知識。
一). 獲取一個聯系人的詳細信息
要獲得一個聯系人的所有信息,需要搜索 ContactsContract.Data 表的每一行,看是否包含有聯系人的 LOOKUP_KEY 。這一列可在 ContactsContract.Data 中獲得,因為Contacts Provider在 ContactsContract.Contacts 表和 ContactsContract.Data 表之間執行了一個隱式的連接。列 LOOKUP_KEY 的詳細信息在上一節課中 (博客鏈接: http://www.cnblogs.com/jdneo/p/3674830.html ) 已經講授過了。
Note:
獲取某一個聯系人的所有信息會降低設備的性能,因為它需要獲取 ContactsContract.Data 表中所有列的數據。在你使用這一方法前要考慮到它對性能的影響。
請求權限
要從Contacts Provider中讀取數據,你的應用必須具有 READ_CONTACTS 權限。要請求這一權限,在清單文件的 <manifest> 標簽中添加如下子標簽:
< uses-permission android:name ="android.permission.READ_CONTACTS" />
配置一個投影
根據每一行所包含的的數據類型,它可能使用一些列或很多列。另外,數據類型的不同會導致數據再不同的列中。要保證你能獲得對于所有可能數據類型所對應的所有可能的列,你需要添加所有的列名到你的投影中。同時,如果要把結果 Cursor 和一個 ListView 綁定起來,要獲取 Data._ID ;否則,綁定不會產生效果。同時要獲取 Data.MIMETYPE 這樣你就可以標示出你獲得的每一行數據的類型,例如:
private static final String PROJECTION = { Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3, Data.DATA4, Data.DATA5, Data.DATA6, Data.DATA7, Data.DATA8, Data.DATA9, Data.DATA10, Data.DATA11, Data.DATA12, Data.DATA13, Data.DATA14, Data.DATA15 };
這一投影會為 ContactsContract.Data 表的一行獲取所有的列,使用在 ContactsContract.Data 類中所定義的列名。
或者,你也可以是用在 ContactsContract.Data 類中定義或者從它繼承的其它列常量。注意,列 SYNC1 到列 SYNC4 是被同步適配器使用的,所以他們的數據對我們現在的應用場景而言沒有用。
定義選擇標準
為你的選擇語句定義一個常量,它是一個保存選擇語句的數組,以及一個保存對應值的變量。使用 Contacts.LOOKUP_KEY 列來尋找聯系人,例如:
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?" ; // Defines the array to hold the search criteria private String[] mSelectionArgs = { "" }; /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private String mLookupKey;
在你的選擇語句中使用“?”作為占位符,能保證搜索語句是由綁定生成的而不是編譯生成的。這可以防止惡意的SQL注入攻擊。
定義排列順序
為結果 Cursor 定義你期望的排列順序。要讓某一類型數據的所有行根據 Data.MIMETYPE 來排列。這一語句會讓所有email的行放在一起,所有電話號碼的行放在一起,等等。例如:
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = Data.MIMETYPE;
Note:
一些數據類型不使用子類,所以你不能用子類型來排序。相反的,你需要再返回的 Cursor 中進行迭代,確定當前行的數據類型,然后將使用子類型的行的數據保存起來。當你完成讀cursor后,之后你就可以通過子類型排序并顯示結果。
初始化加載器
通常,我們在后臺線程從Contacts Provider(以及其它所有的內容提供器)獲取數據。使用由 LoaderManager 類,以及 LoaderManager.LoaderCallbacks 接口所定義的加載器框架來執行后臺的獲取操作。
當你準備好獲取行后,通過調用 initLoader() 初始化加載器框架。將一個整形標識傳遞給該方法;這一標志會傳遞給 LoaderManager.LoaderCallbacks 方法。它可以幫助你區分這些加載器,從而在一個應用中使用多個加載器。
下面的代碼樣例展示了如何初始化這個加載器框架:
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks <Cursor> { ... // Defines a constant that identifies the loader DETAILS_QUERY_ID = 0 ; ... /* * Invoked when the parent Activity is instantiated * and the Fragment's UI is ready. Put final initialization * steps here. */ @Override onActivityCreated(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null , this );
實現 onCreateLoader()
實現 onCreateLoader() 方法,它會在你調用了 initLoader() 后被加載器框架調用。該方法返回一個 CursorLoader 。因為你在搜索 ContactsContract.Data 表,所以使用 Data.CONTENT_URI 常量作為內容URI。例如:
@Override public Loader<Cursor> onCreateLoader( int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter mSelectionArgs[0] = mLookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, mSelectionArgs, SORT_ORDER ); ... }
實現onLoadFinished()和onLoaderReset()
實現 onLoadFinished() 方法。當Contacts Provider將查詢結果返回后,加載器框架會調用 onLoadFinished() 。例如:
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * Process the resulting Cursor here. */ } break ; ... } }
當加載器檢測到結果中的數據發生了變化,那么 onLoaderReset() 方法會被調用,此時,將所有存在的 Cursor 引用設置成null來移除它們。如果你不這么做,加載器框架不會銷毀老的 Cursor ,這樣會導致內存泄露,例如:
@Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * If you have current references to the Cursor, * remove them here. */ } break ; }
二). 獲取一個聯系人的特定數據
要獲取一個聯系人的特定數據,比如email,和檢索所有的詳細數據類似,你需要做的改變僅僅是實現課程 Retrieve All Details for a Contact (博客鏈接: http://www.cnblogs.com/jdneo/p/3674830.html ) 中列出的代碼:
投影
修改你的投影,使得列對應于特定的要搜索的數據類型。同時修改投影,使用在 ContactsContract.CommonDataKinds 子類中對應于數據類型的列常量名。
選擇
修改選擇語句,搜索對應于你的數據類型的 MIMETYPE 值。
排列順序
因為你值使用單一的詳細數據類型,所以不需要根據 Data.MIMETYPE 將返回的 Cursor 分類。
這些修改在下列章節中描述。
定義一個投影
定義你要獲取的列,使用 ContactsContract.CommonDataKinds 子類中對應于數據類型的列常量名。如果你想要將 Cursor 綁定到一個 ListView 上,要確保獲取“ _ID ”列。例如,要獲取email數據,定義下列投影:
private static final String[] PROJECTION = { Email._ID, Email.ADDRESS, Email.TYPE, Email.LABEL };
注意這一投影使用 ContactsContract.CommonDataKinds.Email 類中定義的列名,而不是在類 ContactsContract.Data 中定義的列名。使用email的特定列名可以增加代碼的可讀性。
在投影中,你也可以使用在 ContactsContract.CommonDataKinds 子類中定義的其它列。
定義選擇標準
定義一個搜索表達式,它獲取你想要的特定聯系人的 LOOKUP_KEY 和 Data.MIMETYPE 行數據。對于 MIMETYPE 的值對應的常量,用單引號(')將它括起來;否則,提供器會把常量認為是一個變量名而不是一個字符串值。你不需要為它使用一個占位符,因為你使用的是一個常量而不是一個用戶提供的值。例如:
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private static final String SELECTION = Data.LOOKUP_KEY + " = ?" + " AND " + Data.MIMETYPE + " = " + "'" + Email.CONTENT_ITEM_TYPE + "'" ; // Defines the array to hold the search criteria private String[] mSelectionArgs = { "" };
定義排列順序
為返回的 Cursor 定義一個排列順序。因為你獲得的是一個特定的數據類型,所以略過對 MIMETYPE 排序。另外,如果你正在搜索的詳細數據包含有一個子類型,可以對他排序。例如,對于Email數據你可以根據 Email.TYPE 來排序:
private static final String SORT_ORDER = Email.TYPE + " ASC ";
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
