本课介绍了如何使用以下方法检索数据与某个搜索字符串完全匹配或部分匹配的联系人列表:
- 匹配联系人姓名
- 检索姓名数据与搜索字符串完全匹配或部分匹配的一系列联系人。联系人提供程序允许同一姓名存在多个实例,因此这种方法可能会返回一系列匹配项。
- 匹配特定类型的数据,例如电话号码
- 通过将搜索字符串与特定类型的详细信息进行匹配来检索联系人列表 电子邮件地址等数据。例如,通过这种方法,您可以列出 电子邮件地址与搜索字符串匹配的联系人。
- 匹配任何类型的数据
- 通过将搜索字符串与任何类型的详细数据进行匹配来检索联系人列表, 包括姓名、电话号码、街道地址和电子邮件地址等。例如: 针对某个搜索字符串,您可以接受任何类型的数据,然后列出 数据与字符串匹配的联系人。
注意:本课中的所有示例均使用
CursorLoader
,用于从 Google 通讯录中检索数据。
提供商。CursorLoader
在一个独立于界面线程的线程上运行其查询。这样可确保查询不会降低界面的运行速度
响应速度,并导致糟糕的用户体验。如需了解详情,请参阅在后台加载数据这一 Android 培训课程。
请求读取提供程序的权限
要对联系人提供程序执行任何类型的搜索,您的应用必须具有
READ_CONTACTS
权限。
要请求此功能,请添加以下代码
<uses-permission>
作为
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
按姓名匹配联系人并列出结果
此方法尝试将搜索字符串与联系人提供程序的 ContactsContract.Contacts
表中的一个或多个联系人姓名匹配。您一般需要在 ListView
中显示这些结果,以便用户在匹配的联系人中进行选择。
定义 ListView 和项布局
如需在 ListView
中显示搜索结果,您需要一个主布局文件
用于定义整个界面(包括 ListView
和项布局)
文件,用于定义 ListView
中的一行。例如,您可以使用以下 XML 创建主布局文件 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"/>
此 XML 使用内置的 Android ListView
widget
android:id/list
。
使用以下 XML 定义项布局文件 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"/>
此 XML 使用内置的 Android TextView
微件 android:text1
。
注意:本课并未介绍从 user,因为您可能需要间接获取字符串。例如,您可以向用户 用于搜索姓名与收到的短信中的某个字符串匹配的联系人的选项。
您编写的两个布局文件定义了显示 ListView
的界面。下一步是编写使用此界面显示联系人列表的代码。
定义显示联系人列表的 Fragment
如需显示联系人列表,请先定义一个通过 Activity
加载的 Fragment
。使用
Fragment
是一种更灵活的方法,因为您可以使用
一个 Fragment
用于显示列表,另一个用于显示列表
Fragment
,用于显示用户
选择。通过这种方法,您可以将
课程与
检索联系人的详细信息。
如需了解如何使用 Activity
中的一个或多个 Fragment
对象,请阅读使用 Fragment 构建动态界面这一培训课程。
为了帮助您编写针对联系人提供程序的查询,Android 框架提供了一个
名为 ContactsContract
的协定类,该类定义了
常量和方法来访问提供程序。使用此类时,无需为内容 URI、表格名称或列定义您自己的常量。要使用此类,
添加以下语句:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
由于代码使用 CursorLoader
从提供程序检索数据,因此您必须指定它实现加载器接口 LoaderManager.LoaderCallbacks
。此外,为帮助检测用户从搜索结果列表中选择哪些联系人,请实现适配器接口 AdapterView.OnItemClickListener
。例如:
Kotlin
... import android.support.v4.app.Fragment import android.support.v4.app.LoaderManager import android.widget.AdapterView ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Java
... 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 {
定义全局变量
定义代码的其他部分中使用的全局变量:
Kotlin
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private val FROM_COLUMNS: Array<String> = arrayOf( if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY } else { ContactsContract.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 val TO_IDS: IntArray = intArrayOf(android.R.id.text1) ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { ... // Define global mutable variables // Define a ListView object lateinit var contactsList: ListView // Define variables for the contact the user selects // The contact's _ID value var contactId: Long = 0 // The contact's LOOKUP_KEY var contactKey: String? = null // A content URI for the selected contact var contactUri: Uri? = null // An adapter that binds the result Cursor to the ListView private val cursorAdapter: SimpleCursorAdapter? = null
Java
... /* * 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 ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.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 contactsList; // Define variables for the contact the user selects // The contact's _ID value long contactId; // The contact's LOOKUP_KEY String contactKey; // A content URI for the selected contact Uri contactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter cursorAdapter; ...
注意:由于
Contacts.DISPLAY_NAME_PRIMARY
需要 Android 3.0(API 版本 11)或更高版本,
应用的 minSdkVersion
到 10 或更低版本时,系统会在
Android Studio。如需关闭这条警告,可在 FROM_COLUMNS
的定义前面添加注解 @SuppressLint("InlinedApi")
。
初始化 Fragment
初始化 Fragment
。添加 Android 系统所需的空的公开构造函数,并在回调方法 onCreateView()
中扩充 Fragment
对象的界面。例如:
Kotlin
// A UI Fragment must inflate its View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false) }
Java
// 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
。获取 ListView
对象
调用 Activity.findViewById()
,您需要使用
Fragment
。使用 Context
(当您调用 setAdapter()
时)。
例如:
Kotlin
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) ... // Gets the ListView from the View list of the parent activity activity?.also { contactsList = it.findViewById<ListView>(R.id.contact_list_view) // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView contactsList.adapter = cursorAdapter } }
Java
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity contactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView contactsList.setAdapter(cursorAdapter); }
设置选定的联系人监听器
在显示搜索结果时,您通常希望能够允许用户选择一位联系人以进一步处理。例如,当用户点击某个联系人时,您可以
在地图上显示联系人的地址。如需提供此功能,您首先需要将当前 Fragment
定义为点击监听器(可通过指定该类实现 AdapterView.OnItemClickListener
执行此操作),如定义显示联系人列表的 Fragment 部分所示。
如需继续设置监听器,请通过以下方法将其绑定到 ListView
在 onActivityCreated()
中调用 setOnItemClickListener()
方法。例如:
Kotlin
fun onActivityCreated(savedInstanceState:Bundle) { ... // Set the item click listener to be the current fragment. contactsList.onItemClickListener = this ... }
Java
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. contactsList.setOnItemClickListener(this); ... }
由于您指定当前 Fragment
为 ListView
的 OnItemClickListener
,因此您现在需要实现其所需的方法 onItemClick()
,此方法会处理点击事件。后面的部分会对此进行说明。
定义映射
定义一个常量,该常量包含要从查询中返回的列。以下项中的每一项
ListView
会显示联系人的显示名称,
,其中包含主要形式的联系人姓名。在 Android 3.0(API 版本 11)及更高版本中,
此列的名称为
Contacts.DISPLAY_NAME_PRIMARY
;在之前的版本中,其名称为
Contacts.DISPLAY_NAME
。
列 Contacts._ID
由 SimpleCursorAdapter
绑定进程使用。将 Contacts._ID
和 LOOKUP_KEY
结合使用可为用户选择的联系人构建内容 URI。
Kotlin
... @SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Contacts.DISPLAY_NAME_PRIMARY else ContactsContract.Contacts.DISPLAY_NAME )
Java
... @SuppressLint("InlinedApi") private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME };
为 Cursor 列索引定义常量
如需从 Cursor
中的单个列获取数据,您需要 Cursor
中该列的索引。你可以定义
针对 Cursor
列的索引,因为索引是
与映射中列名称的顺序相同。例如:
Kotlin
// The column index for the _ID column private const val CONTACT_ID_INDEX: Int = 0 // The column index for the CONTACT_KEY column private const val CONTACT_KEY_INDEX: Int = 1
Java
// The column index for the _ID column private static final int CONTACT_ID_INDEX = 0; // The column index for the CONTACT_KEY column private static final int CONTACT_KEY_INDEX = 1;
指定选择条件
如需指定所需的数据,请创建文本表达式和变量的组合,告知提供程序要搜索的数据列及要查找的值。
对于文本表达式,请定义一个列出搜索列的常量。虽然 表达式也可以包含值,推荐的做法是使用 “?”占位符。在检索期间,该占位符会被替换为 数组。使用“?”作为占位符,可确保搜索规范是通过 而不是通过 SQL 编译。这种做法消除了 注入。例如:
Kotlin
// Defines the text expression @SuppressLint("InlinedApi") private val SELECTION: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?" else "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?" ... // Defines a variable for the search string private val searchString: String = ... // Defines the array to hold values that replace the ? private val selectionArgs = arrayOf<String>(searchString)
Java
// 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 searchString; // Defines the array to hold values that replace the ? private String[] selectionArgs = { searchString };
定义 onItemClick() 方法
在上一部分中,您为 ListView
设置了项点击监听器。现在,可通过定义方法 AdapterView.OnItemClickListener.onItemClick()
实现对监听器的操作:
Kotlin
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) { // Get the Cursor val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply { // Move to the selected contact moveToPosition(position) // Get the _ID value contactId = getLong(CONTACT_ID_INDEX) // Get the selected LOOKUP KEY contactKey = getString(CONTACT_KEY_INDEX) // Create the contact's content Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey) /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ } }
Java
@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 contactId = cursor.getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY contactKey = cursor.getString(CONTACT_KEY_INDEX); // Create the contact's content Uri contactUri = Contacts.getLookupUri(contactId, mContactKey); /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ }
初始化加载器
由于您使用 CursorLoader
来检索数据,因此您必须初始化后台线程以及其他控制异步检索的变量。在
以onCreate()
的身份使用
如以下示例中所示:
Kotlin
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { // Always call the super method first super.onCreate(savedInstanceState) ... // Initializes the loader loaderManager.initLoader(0, null, this)
Java
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onCreate(Bundle savedInstanceState) { // Always call the super method first super.onCreate(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
实现 onCreateLoader()
实现 onCreateLoader()
方法,加载器框架会在您调用 initLoader()
之后立即调用此方法。
在 onCreateLoader()
中,设置搜索字符串格式。如需为字符串指定格式,请插入“%”(百分号)字符以表示零个或更多个字符序列,或插入“_”(下划线)字符以表示单个字符,或者同时插入这两种字符。例如,“%Jefferson%”格式会同时匹配“Thomas Jefferson”和“Jefferson Davis”。
从此方法返回一个新的 CursorLoader
。对于内容
URI,请使用 Contacts.CONTENT_URI
。
此 URI 引用整个表,如以下示例所示:
Kotlin
... override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%$mSearchString%" // Starts the query return activity?.let { return CursorLoader( it, ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%" + searchString + "%"; // Starts the query return new CursorLoader( getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
实现 onLoadFinished() 和 onLoaderReset()
实现 onLoadFinished()
方法。当联系人提供程序返回查询结果时,加载器框架会调用 onLoadFinished()
。在此方法中,将
在以下位置找到第 Cursor
条结果:
SimpleCursorAdapter
。这会使用搜索结果自动更新 ListView
:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter.swapCursor(cursor); }
当加载器框架检测到以下事件时,会调用 onLoaderReset()
方法:
结果 Cursor
包含过时数据。删除对现有 Cursor
的 SimpleCursorAdapter
引用。否则,加载器框架将不会
回收利用 Cursor
,从而导致内存泄漏。例如:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { // Delete the reference to the existing Cursor cursorAdapter?.swapCursor(null) }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor cursorAdapter.swapCursor(null); }
现在,您已经有了应用的关键部分,该部分将搜索字符串与联系人姓名匹配,并在 ListView
中返回结果。用户可以点击联系人姓名将其选中。
这会触发监听器,您可以在其中进一步处理联系人的数据。例如,您可以检索联系人的详细信息。如需了解如何执行此操作,请继续学习下一课:检索联系人的详细信息。
如需详细了解搜索界面,请参阅 API 指南 创建搜索界面。
本课的其余部分介绍了在联系人提供程序中查找联系人的其他方法。
按特定类型的数据匹配联系人
通过使用这种方法,您可以指定要匹配的数据类型。正在检索 “按名称排序”就是此类查询的一个具体示例,但您也可以针对任何 与联系人相关的详细数据相关联。例如,您可以检索具有特定邮政编码的联系人;在这种情况下,搜索字符串必须与存储在邮政编码行中的数据匹配。
要实现此类检索,请先实现以下代码,如 前面部分:
- 请求读取提供程序的权限。
- 定义 ListView 和项布局。
- 定义显示联系人列表的 Fragment。
- 定义全局变量。
- 初始化 Fragment。
- 为 ListView 设置 CursorAdapter。
- 设置选定的联系人监听器。
-
为 Cursor 列索引定义常量。
虽然您是从其他表中检索数据,但各表中列的顺序 投影是相同的,因此您可以为 Cursor 使用相同的索引。
- 定义 onItemClick() 方法。
- 初始化加载器。
- 实现 onLoadFinished() 和 onLoaderReset()。
下面的步骤显示了将搜索字符串与特定类型的详细数据匹配并显示结果所需的其他代码。
选择数据类型和表
如需搜索特定类型的详细数据,您必须知道该数据类型的自定义 MIME 类型值。每种数据类型都有一个唯一的 MIME 类型
值由常量 CONTENT_ITEM_TYPE
定义,该常量位于
与数据类型关联的 ContactsContract.CommonDataKinds
。
子类的名称可表明其数据类型;例如,email 的子类,
数据为 ContactsContract.CommonDataKinds.Email
,且自定义 MIME
电子邮件数据的类型由常量定义,
Email.CONTENT_ITEM_TYPE
。
使用 ContactsContract.Data
表进行搜索。该表格定义或继承了您的映射、选择子句和排序顺序所需的所有常量。
定义映射
要定义投影,请选择
ContactsContract.Data
或其继承的类。通过
联系人提供程序在 ContactsContract.Data
之间进行隐式联接
和其他表,然后再返回行。例如:
Kotlin
@SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Data.DISPLAY_NAME_PRIMARY else ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY )
Java
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact };
定义搜索条件
要在特定类型的数据中搜索字符串,请根据以下内容构造一个选择子句: 以下:
-
包含该搜索字符串的列名称。此名称因数据类型而异
因此您需要找到
与数据类型对应的
ContactsContract.CommonDataKinds
然后从该子类中选择列名称。例如,如需搜索电子邮件地址,请使用Email.ADDRESS
列。 - 搜索字符串本身,以“?”字符。
-
包含自定义 MIME 类型值的列名称。此名称始终为
Data.MIMETYPE
。 -
该数据类型的自定义 MIME 类型值。如前所述,这是
CONTENT_ITEM_TYPE
常量,该常量位于ContactsContract.CommonDataKinds
子类中。例如,电子邮件地址数据的 MIME 类型值是Email.CONTENT_ITEM_TYPE
。通过将“'
”(英文单引号)字符连接到常量的开头和结尾,将值用英文单引号引起来;否则,提供程序会将值解读为变量名称,而不是字符串值。 您不需要为此值使用占位符,因为您使用的是常量,而不是用户提供的值。
例如:
Kotlin
/* * Constructs search criteria from the search string * and email MIME type */ private val SELECTION: String = /* * 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. */ "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
Java
/* * 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. */ ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
接下来,定义变量以包含选择参数:
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
实现 onCreateLoader()
现在,您已经指定了所需的数据及其查找方式,请在
onCreateLoader()
的实现。
返回一个新的 CursorLoader
方法,将投影、选择文本表达式和选择数组用作
参数。对于内容 URI,请使用 Data.CONTENT_URI
。例如:
Kotlin
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // OPTIONAL: Makes search string into pattern searchString = "%$mSearchString%" searchString?.also { // Puts the search string into the selection criteria selectionArgs[0] = it } // Starts the query return activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern searchString = "%" + searchString + "%"; // Puts the search string into the selection criteria selectionArgs[0] = searchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
这些代码段是基于特定类型的详细信息进行简单反向查找的基础 数据。如果您的应用侧重于特定类型的数据(例如电子邮件地址),并且您希望用户能够获取与某条数据相关的姓名,那么这无疑是最理想的方法。
按任何类型的数据匹配联系人
根据任何类型的数据检索联系人,如果联系人的任何数据与 搜索字符串,包括姓名、电子邮件地址、邮政地址、电话号码等。 这会产生广泛的搜索结果。例如,如果搜索字符串 为“Doe”,则搜索任意数据类型会返回联系人“John Doe”;它也会返回 住在 "Doe Street" 的联系人。
要实现此类检索,请先实现以下代码,如 前面部分:
- 请求读取提供程序的权限。
- 定义 ListView 和项布局。
- 定义显示联系人列表的 Fragment。
- 定义全局变量。
- 初始化 Fragment。
- 为 ListView 设置 CursorAdapter。
- 设置选定的联系人监听器。
- 定义投影。
-
为 Cursor 列索引定义常量。
对于这种类型的检索,您可以使用在按姓名匹配联系人并列出结果部分所用的那个表。使用 相同的列索引。
- 定义 onItemClick() 方法。
- 初始化加载器。
- 实现 onLoadFinished() 和 onLoaderReset()。
下面的步骤显示了将搜索字符串与任何类型的数据匹配并显示结果所需的其他代码。
移除选择条件
不要定义 SELECTION
常量或 mSelectionArgs
变量。
此类检索中不使用这些内容。
实现 onCreateLoader()
实现 onCreateLoader()
方法,返回一个新的 CursorLoader
。您不需要将搜索字符串转换为格式,因为联系人提供程序会自动执行该操作。使用
将 Contacts.CONTENT_FILTER_URI
用作基本 URI,并通过调用
Uri.withAppendedPath()
。使用此 URI 会自动触发对任何类型数据的搜索,如以下示例所示:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ val contentUri: Uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(searchString) ) // Starts the query return activity?.let { CursorLoader( it, contentUri, PROJECTION2, null, null, null ) } ?: throw IllegalStateException() }
Java
@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(searchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
这些代码段是对联系人提供程序进行广泛搜索的应用的基础。 这种方法适用于希望实现与“通讯录”应用中的通讯录列表屏幕功能相似的应用。