【翻译】通讯录数据的存取(一)——获取通讯录列表
来源:互联网 发布:兰州大学网络教育网址 编辑:程序博客网 时间:2024/05/18 03:04
通讯录数据的存取
有选择性的翻译自:https://developer.android.com/training/contacts-provider/index.html
Contacts Provider是用户通信信息仓库,包含通讯录应用程序和社交网络应用程序的数据。我们可以通过直接调用ContactsResolver的方法或直接发送调用通讯录应用程序的intent来获取Contacts Provider提供的信息。
目录
- 通讯录数据的存取
- 目录
- 获取通讯录列表
- 匹配通信人姓名
- 定义ListView的布局
- 定义Fragment展示通信人列表
- 定义全局变量
- 初始化Fragment
- 给ListView设置CursorAdapter
- 设置点击通讯录列表的监听器
- 定义一个规划projection
- 定义Cursor列的索引值常量
- 定义选择标准
- 定义onItemClick方法
- 初始化CursorLoader
- 实现onCreateLoader
- 实现onLoadFinished和onLoadReset
- 匹配某类型数据
- 选择数据类型和表
- 定义一个规划projection
- 定义选择标准
- 实现onCreateLoader
- 匹配任意数据
- 去除选择标准
- 实现onCreateLoader
- 匹配通信人姓名
获取通讯录列表
根据以下三种类型匹配获取列表:
- 匹配通信人姓名
- 匹配某类型数据,如电话号码
- 匹配任意数据
在使用之前需要申请如下权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />
匹配通信人姓名
实现方案是将字符串与通讯录提供者(Contact Provider)的ContactsContract.Contacts表的一个或多个通信人的姓名进行匹配。
这里以ListView来展示结果为例介绍整个过程。
定义ListView的布局
创建整体布局文件: res/layout/contacts_list_view.xml:
<?xml version="1.0" encoding="utf-8"?><ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
该文件使用内置的Android ListView组件android:id/list.
然后定义每一项的布局文件 contacts_list_item.xml :
<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"/>
该文件使用内置的Android TextView组件:android:text1.
接下来定义使用上述UI展示通信人列表的代码。
定义Fragment展示通信人列表
为了更好的帮助开发者查询Contacts Provider,Android框架提供了名为ContactsContract的协议类,它定义了用来存取provider的常量和方法。使用该类,你无需定义URI,表名或列名等常量。
我们使用CursorLoader 从provider获取数据, 因此必须实现接口:LoaderManager.LoaderCallbacks. 另外,实现AdapterView.OnItemClickListener 以获取用户在搜索列表中选择的联系人信息。相应代码如下:
...import android.support.v4.app.Fragment;import android.support.v4.app.LoaderManager.LoaderCallbacks;import android.widget.AdapterView;...public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
定义全局变量
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private final static String[] FROM_COLUMNS = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME }; /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private final static int[] TO_IDS = { android.R.id.text1 }; // Define global mutable variables // Define a ListView object ListView mContactsList; // Define variables for the contact the user selects // The contact's _ID value long mContactId; // The contact's LOOKUP_KEY String mContactKey; // A content URI for the selected contact Uri mContactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter mCursorAdapter; ...
初始化Fragment
添加空的结构体,然后在onCreateView()中加载Fragment对象的UI。如下:
// Empty public constructor, required by the system public ContactsFragment() {} // A UI Fragment must inflate its View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false); }
给ListView设置CursorAdapter
使用SimpleCursorAdapter 将搜索结果与ListView关联。如下:
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter mCursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView mContactsList.setAdapter(mCursorAdapter); }
设置点击通讯录列表的监听器
当展示了搜索列表后,我们会允许用户点击某一联系人以做进一步的操作。如,当用户点击联系人后,在地图上显示联系人的地址。为做到这一点,首先定义一个实现了AdapterView.OnItemClickListener 接口的Fragment,就像在定义Fragment展示通信人列表*这一节中所讲的。
然后在onActivityCreated()中调用setOnItemClickListener()将监听器与ListView做关联。如:
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. mContactsList.setOnItemClickListener(this); ... }
定义一个规划(projection)
定义一个常量,包含所有你打算返回的列名。如:
...@SuppressLint("InlinedApi")private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME };
其中,列名Contacts._ID会在SimpleCursorAdapter 绑定过程中用到。Contacts._ID和 LOOKUP_KEY 一起用来构造用户选取的联系人的内容URI。 而ListView在展示联系人列表时会用到联系人姓名。该列在Android 3.0(API 11)及以后,列名叫Contacts.DISPLAY_NAME_PRIMARY,之前叫Contacts.DISPLAY_NAME。
定义Cursor列的索引值常量
获取某cursor某列的数据时,需要该列在Cursor中的列索引值。因为该索引值使用的是上一节定义的规划中的列的顺序,因此可以把列的索引值定义为常量。
// The column index for the _ID columnprivate static final int CONTACT_ID_INDEX = 0;// The column index for the LOOKUP_KEY columnprivate static final int LOOKUP_KEY_INDEX = 1;
定义选择标准
使用文字表达式指出要搜索的数据列,尽管该表达式可以包含参数值,推荐使用占位符“?”来代替参数值。使用“?”可以保证搜索通过连接而不是SQL编译来生成,避免恶意SQL注入的可能性。
使用变量来表示待搜索的内容,即SQL中替换“?”的内容。代码如下:
// Defines the text expression @SuppressLint("InlinedApi") private static final String SELECTION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" : Contacts.DISPLAY_NAME + " LIKE ?"; // Defines a variable for the search string private String mSearchString; // Defines the array to hold values that replace the ? private String[] mSelectionArgs = { mSearchString };
定义onItemClick()方法
实现上一节的监听器,如下:
@Override public void onItemClick( AdapterView<?> parent, View item, int position, long rowID) { // Get the Cursor Cursor cursor = parent.getAdapter().getCursor(); // Move to the selected contact cursor.moveToPosition(position); // Get the _ID value mContactId = getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY mContactKey = getString(CONTACT_KEY_INDEX); // Create the contact's content Uri mContactUri = Contacts.getLookupUri(mContactId, mContactKey); /* * You can use mContactUri as the content URI for retrieving * the details for a contact. */ }
初始化CursorLoader
既然使用CursorLoader 来获取数据,必须初始化控制异步获取数据的后台线程和其他变量。在onActivityCreated()方法中做初始化,该函数会在Fragment的UI出现之前被调用。如下:
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onActivityCreated(Bundle savedInstanceState) { // Always call the super method first super.onActivityCreated(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
实现onCreateLoader()
该方法会在我们调用initLoader()后立即被系统调用。
在onCreateLoader()中,设置搜索串模式。字符串中插入:“%”表示0或更多个字符串,“_”代表一个字符。如,模式”%Jefferson%”会匹配“Thomas Jefferson”和”Jefferson Davis”. 至于内容URI,使用Contacts.CONTENT_URI, 它指向整个表。代码如下:
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ mSelectionArgs[0] = "%" + mSearchString + "%"; // Starts the query return new CursorLoader( getActivity(), Contacts.CONTENT_URI, PROJECTION, SELECTION, mSelectionArgs, null ); }
实现onLoadFinished()和onLoadReset()
Loader框架在Contacts Provider返回搜索结果时调用onLoadFinished().在该方法中,将结果Cursor放入SimpleCursorAdapter中,这样会自动使用搜索结果更新ListView:
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView mCursorAdapter.swapCursor(cursor); }
onLoaderReset()方法会在loader框架发现Cursor结果包含旧数据时被调用。在该方法中,需要清除SimpleCursorAdapter对已有Cursor的引用,否则loader框架不会回收该Cursor,会引起内存泄漏。
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor mCursorAdapter.swapCursor(null); }
至此,已经讲完了搜索通信人姓名并将搜索结果在ListView中展现的所有关键点。
匹配某类型数据
实现这一类型的数据获取,首先需要像上一节一样实现以下代码:
- 申请度通讯录的权限
- 定义ListView的布局
- 定义Fragment展示通信人列表
- 定义全局变量
- 初始化Fragment
- 给ListView设置CursorAdapter
- 设置点击通讯录列表的监听器
- 定义Cursor列的索引值常量
- 定义onItemClick方法
- 初始化CursorLoader
- 实现onLoadFinished和onLoadReset
除上述步骤外,需要额外的代码来获取匹配某些类型数据的通讯录信息。接下来是与上一节实现方面有不同的步骤。
选择数据类型和表
搜索某类型的具体数据,需要知道该类型对应的MIME类型。所有的数据类型都有一个唯一的MIME类型值,该值是ContactsContract.CommonDataKinds 中与数据类型匹配的子类中定义的常量CONTENT_ITEM_TYPE。如,Email数据对应的子类是ContactsContract.CommonDataKinds.Email, 而它的MIME类型是Email.CONTENT_ITEM_TYPE常量.
选择完数据类型后,选择该使用哪个表。使用ContactsContract.Data表,该表中定义或继承了所有需要查询的列名或如何排序等常量。
定义一个规划(projection)
可以选择ContactsContract.Data或它继承的类中的一个或多个列。Contacts Provider在返回结果前会对ContactsContract.Data表和其他表做一个隐式的连接。如下:
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Data.DISPLAY_NAME_PRIMARY : Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI Data.LOOKUP_KEY };
定义选择标准
使用如下数据构造一个搜索语句:
- 包含待搜索字符串信息的列的名字 根据搜索类型的不同而变化,因此需要先找出与搜索类型对应的ContactsContract.CommonDataKinds 的子类,然后选择该子类的列名。如,使用列名Email.ADDRESS来搜索email地址。
- 搜索字符串 在搜索语句中使用“?”来代替。
- 包含MIME类型的列名 该值是固定值:Data.MIMETYPE.
- 搜索类型对应的MIME值 ContactsContract.CommonDataKinds 中与数据类型匹配的子类中定义的常量CONTENT_ITEM_TYPE。如,Email数据对应的子类是ContactsContract.CommonDataKinds.Email, 而它的MIME类型是Email.CONTENT_ITEM_TYPE常量. 需要使用单引号将该常量括起来,否则provider会把它当作变量名而不是常量。
代码如下:
/* * Constructs search criteria from the search string * and email MIME type */ private static final String SELECTION = /* * Searches for an email address * that matches the search string */ Email.ADDRESS + " LIKE ? " + "AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
接下来定义包含搜索参数的变量:
String mSearchString; String[] mSelectionArgs = { "" };
实现onCreateLoader
与上一节不同的是,这里的内容URI,使用Data.CONTENT_URI.如下:
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern mSearchString = "%" + mSearchString + "%"; // Puts the search string into the selection criteria mSelectionArgs[0] = mSearchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, mSelectionArgs, null ); }
至此,匹配某类型数据的搜索实现已结束。
匹配任意数据
返回匹配某数据的联系人列表,而不管该数据是名字,Email地址,通信地址或电话号码等。
实现这一类型的数据获取,首先需要像上一节一样实现以下代码:
- 申请度通讯录的权限
- 定义ListView的布局
- 定义Fragment展示通信人列表
- 定义全局变量
- 初始化Fragment
- 给ListView设置CursorAdapter
- 设置点击通讯录列表的监听器
- 定义一个规划(projection)
- 定义Cursor列的索引值常量
- 定义onItemClick方法
- 初始化CursorLoader
- 实现onLoadFinished和onLoadReset
接下来是与上一节实现方面有不同的步骤。
去除选择标准
不用定义SELECTION常量或mSelectionArgs变量。
实现onCreateLoader
不再需要将字符串转换为模式,因为Contacts Provider会自动为你做。使用Contacts.CONTENT_FILTER_URI作为基础URI, 通过调用Uri.withAppendedPath()将待搜索字符串追加到上述URI. 使用处理后的URI来搜索任意类型的数据。代码如下:
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ Uri contentUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, Uri.encode(mSearchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
至此,匹配任意类型数据的搜索实现已结束。
- 【翻译】通讯录数据的存取(一)——获取通讯录列表
- 通讯录数据的存取(二)—— 获取通讯录的具体信息
- 通讯录数据的存取(三)—— 使用Intent修改通讯录
- 通讯录数据的存取(四)——Contact Badge的使用
- iOS 获取通讯录的数据
- 获取系统通讯录列表的方法
- 通讯录(一)——通讯录所有列的名字和作用
- 获取手机通讯录-----1.1(取出通讯录数据)
- Android通讯录数据获取
- iOS_获取通讯录数据
- 安卓小渣渣的成长之路1.0——使用SimpleCursorAdapter添加列表视图内容(获取手机通讯录名字)
- 类似通讯录的列表
- android 获取通讯录记录列表
- android 获取通讯录记录列表
- swift获取手机通讯录列表
- 通讯录的内容提供者(查询手机通讯录的数据)
- PhoneGap API帮助文档翻译—Contacts(通讯录)
- PhoneGap API帮助文档翻译—Contacts(通讯录)
- HeadFrist设计模式学习之适配器模式
- 想做一个视频在线直播系统
- include相关问题
- LCA
- hdu 5713 K个联通块 2016百度之星复赛1002 DP
- 【翻译】通讯录数据的存取(一)——获取通讯录列表
- android系统重启流程分析
- Android绘图机制与处理技巧(四)——Android图像处理之画笔特效处理
- PAT 1014 Waiting in Line (模拟)
- mysql utf8mb4编码设置
- spark UI 显示已完成应用的历史信息
- session.flush()与session.clear()的区别及使用环境
- android RSA公钥加密 公钥解密,解决乱码问题
- (面试)操作系统相关(不断丰富中…)