Home | History | Annotate | Download | only in contacts-provider
      1 page.title=Retrieving a List of Contacts
      2 
      3 trainingnavtop=true
      4 @jd:body
      5 
      6 <div id="tb-wrapper">
      7 <div id="tb">
      8 
      9 <!-- table of contents -->
     10 <h2>This lesson teaches you to</h2>
     11 <ol>
     12   <li><a href="#Permissions">Request Permission to Read the Provider</a>
     13   <li><a href="#NameMatch">Match a Contact by Name and List the Results</a></li>
     14   <li><a href="#TypeMatch">Match a Contact By a Specific Type of Data</a></li>
     15   <li><a href="#GeneralMatch">Match a Contact By Any Type of Data</a></li>
     16 </ol>
     17 
     18 <!-- other docs (NOT javadocs) -->
     19 <h2>You should also read</h2>
     20 <ul>
     21     <li>
     22         <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
     23         Content Provider Basics</a>
     24     </li>
     25     <li>
     26         <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
     27         Contacts Provider</a>
     28     </li>
     29     <li>
     30         <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
     31     </li>
     32     <li>
     33         <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>
     34     </li>
     35 </ul>
     36 
     37 <h2>Try it out</h2>
     38 
     39 <div class="download-box">
     40     <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
     41     Download the sample
     42     </a>
     43  <p class="filename">ContactsList.zip</p>
     44 </div>
     45 
     46 </div>
     47 </div>
     48 <p>
     49     This lesson shows you how to retrieve a list of contacts whose data matches all or part of a
     50     search string, using the following techniques:
     51 </p>
     52 <dl>
     53     <dt>Match contact names</dt>
     54     <dd>
     55         Retrieve a list of contacts by matching the search string to all or part of the contact
     56         name data. The Contacts Provider allows multiple instances of the same name, so this
     57         technique can return a list of matches.
     58     </dd>
     59     <dt>Match a specific type of data, such as a phone number</dt>
     60     <dd>
     61         Retrieve a list of contacts by matching the search string to a particular type of detail
     62         data such as an email address. For example, this technique allows you to list all of the
     63         contacts whose email address matches the search string.
     64     </dd>
     65     <dt>Match any type of data</dt>
     66     <dd>
     67         Retrieve a list of contacts by matching the search string to any type of detail data,
     68         including name, phone number, street address, email address, and so forth. For example,
     69         this technique allows you to accept any type of data for a search string and then list the
     70         contacts for which the data matches the string.
     71     </dd>
     72 </dl>
     73 <p class="note">
     74     <strong>Note:</strong> All the examples in this lesson use a
     75     {@link android.support.v4.content.CursorLoader} to retrieve data from the Contacts
     76     Provider. A {@link android.support.v4.content.CursorLoader} runs its query on a
     77     thread that's separate from the UI thread. This ensures that the query doesn't slow down UI
     78     response times and cause a poor user experience. For more information, see the Android
     79     training class <a href="{@docRoot}training/load-data-background/index.html">
     80     Loading Data in the Background</a>.
     81 </p>
     82 <h2 id="Permissions">Request Permission to Read the Provider</h2>
     83 <p>
     84     To do any type of search of the Contacts Provider, your app must have
     85     {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission.
     86     To request this, add this
     87 <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
     88     element to your manifest file as a child element of
     89 <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>:
     90 </p>
     91 <pre>
     92     &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
     93 </pre>
     94 <h2 id="NameMatch">Match a Contact by Name and List the Results</h2>
     95 <p>
     96     This technique tries to match a search string to the name of a contact or contacts in the
     97     Contact Provider's {@link android.provider.ContactsContract.Contacts} table. You usually want
     98     to display the results in a {@link android.widget.ListView}, to allow the user to choose among
     99     the matched contacts.
    100 </p>
    101 <h3 id="DefineListView">Define ListView and item layouts</h3>
    102 <p>
    103     To display the search results in a {@link android.widget.ListView}, you need a main layout file
    104     that defines the entire UI including the {@link android.widget.ListView}, and an item layout
    105     file that defines one line of the {@link android.widget.ListView}. For example, you could create
    106     the main layout file <code>res/layout/contacts_list_view.xml</code> with
    107     the following XML:
    108 </p>
    109 <pre>
    110 &lt;?xml version="1.0" encoding="utf-8"?&gt;
    111 &lt;ListView xmlns:android="http://schemas.android.com/apk/res/android"
    112           android:id="&#64;android:id/list"
    113           android:layout_width="match_parent"
    114           android:layout_height="match_parent"/&gt;
    115 </pre>
    116 <p>
    117     This XML uses the built-in Android {@link android.widget.ListView} widget
    118     {@link android.R.id#list android:id/list}.
    119 </p>
    120 <p>
    121     Define the item layout file <code>contacts_list_item.xml</code> with the following XML:
    122 </p>
    123 <pre>
    124 &lt;?xml version="1.0" encoding="utf-8"?&gt;
    125 &lt;TextView xmlns:android="http://schemas.android.com/apk/res/android"
    126           android:id="&#64;android:id/text1"
    127           android:layout_width="match_parent"
    128           android:layout_height="wrap_content"
    129           android:clickable="true"/&gt;
    130 </pre>
    131 <p>
    132     This XML uses the built-in Android {@link android.widget.TextView} widget
    133     {@link android.R.id#text1 android:text1}.
    134 </p>
    135 <p class="note">
    136     <strong>Note:</strong> This lesson doesn't describe the UI for getting a search string from the
    137     user, because you may want to get the string indirectly. For example, you can give the user
    138     an option to search for contacts whose name matches a string in an incoming text message.
    139 </p>
    140 <p>
    141     The two layout files you've written define a user interface that shows a
    142     {@link android.widget.ListView}. The next step is to write code that uses this UI to display a
    143     list of contacts.
    144 </p>
    145 <h3 id="Fragment">Define a Fragment that displays the list of contacts</h3>
    146 <p>
    147     To display the list of contacts, start by defining a {@link android.support.v4.app.Fragment}
    148     that's loaded by an {@link android.app.Activity}. Using a
    149     {@link android.support.v4.app.Fragment} is a more flexible technique, because you can use
    150     one {@link android.support.v4.app.Fragment} to display the list and a second
    151     {@link android.support.v4.app.Fragment} to display the details for a contact that the user
    152     chooses from the list. Using this approach, you can combine one of the techniques presented in
    153     this lesson with one from the lesson <a href="retrieve-details.html">
    154     Retrieving Details for a Contact</a>.
    155 </p>
    156 <p>
    157     To learn how to use one or more {@link android.support.v4.app.Fragment} objects from an
    158     an {@link android.app.Activity}, read the training class
    159     <a href="{@docRoot}training/basics/fragments/index.html">
    160     Building a Dynamic UI with Fragments</a>.
    161 </p>
    162 <p>
    163     To help you write queries against the Contacts Provider, the Android framework provides a
    164     contracts class called {@link android.provider.ContactsContract}, which defines useful
    165     constants and methods for accessing the provider. When you use this class, you don't have to
    166     define your own constants for content URIs, table names, or columns. To use this class,
    167     include the following statement:
    168 </p>
    169 <pre>
    170 import android.provider.ContactsContract;
    171 </pre>
    172 <p>
    173     Since the code uses a {@link android.support.v4.content.CursorLoader} to retrieve data
    174     from the provider, you must specify that it implements the loader interface
    175     {@link android.support.v4.app.LoaderManager.LoaderCallbacks}. Also, to help detect which contact
    176     the user selects from the list of search results, implement the adapter interface
    177     {@link android.widget.AdapterView.OnItemClickListener}. For example:
    178 </p>
    179 <pre>
    180 ...
    181 import android.support.v4.app.Fragment;
    182 import android.support.v4.app.LoaderManager.LoaderCallbacks;
    183 import android.widget.AdapterView;
    184 ...
    185 public class ContactsFragment extends Fragment implements
    186         LoaderManager.LoaderCallbacks&lt;Cursor&gt;,
    187         AdapterView.OnItemClickListener {
    188 </pre>
    189 <h3 id="DefineVariables">Define global variables</h3>
    190 <p>
    191     Define global variables that are used in other parts of the code:
    192 </p>
    193 <pre>
    194     ...
    195     /*
    196      * Defines an array that contains column names to move from
    197      * the Cursor to the ListView.
    198      */
    199     &#64;SuppressLint("InlinedApi")
    200     private final static String[] FROM_COLUMNS = {
    201             Build.VERSION.SDK_INT
    202                     &gt;= Build.VERSION_CODES.HONEYCOMB ?
    203                     Contacts.DISPLAY_NAME_PRIMARY :
    204                     Contacts.DISPLAY_NAME
    205     };
    206     /*
    207      * Defines an array that contains resource ids for the layout views
    208      * that get the Cursor column contents. The id is pre-defined in
    209      * the Android framework, so it is prefaced with "android.R.id"
    210      */
    211     private final static int[] TO_IDS = {
    212            android.R.id.text1
    213     };
    214     // Define global mutable variables
    215     // Define a ListView object
    216     ListView mContactsList;
    217     // Define variables for the contact the user selects
    218     // The contact's _ID value
    219     long mContactId;
    220     // The contact's LOOKUP_KEY
    221     String mContactKey;
    222     // A content URI for the selected contact
    223     Uri mContactUri;
    224     // An adapter that binds the result Cursor to the ListView
    225     private SimpleCursorAdapter mCursorAdapter;
    226     ...
    227 </pre>
    228 <p class="note">
    229     <strong>Note:</strong> Since
    230     {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    231     Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
    232     app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
    233     Eclipse with ADK. To turn off this warning, add the annotation
    234     <code>@SuppressLint("InlinedApi")</code> before the definition of <code>FROM_COLUMNS</code>.
    235 </p>
    236 <h3 id="InitializeFragment">Initialize the Fragment</h3>
    237 <p>
    238 
    239     Initialize the {@link android.support.v4.app.Fragment}. Add the empty, public constructor
    240     required by the Android system, and inflate the {@link android.support.v4.app.Fragment} object's
    241     UI in the callback method {@link android.support.v4.app.Fragment#onCreateView onCreateView()}.
    242     For example:
    243 </p>
    244 <pre>
    245     // Empty public constructor, required by the system
    246     public ContactsFragment() {}
    247 
    248     // A UI Fragment must inflate its View
    249     &#64;Override
    250     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    251             Bundle savedInstanceState) {
    252         // Inflate the fragment layout
    253         return inflater.inflate(R.layout.contact_list_fragment,
    254             container, false);
    255     }
    256 </pre>
    257 <h3 id="DefineAdapter">Set up the CursorAdapter for the ListView</h3>
    258 <p>
    259     Set up the {@link android.support.v4.widget.SimpleCursorAdapter} that binds the results of the
    260     search to the {@link android.widget.ListView}. To get the {@link android.widget.ListView} object
    261     that displays the contacts, you need to call {@link android.app.Activity#findViewById
    262     Activity.findViewById()} using the parent activity of the
    263     {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
    264     parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
    265     For example:
    266 </p>
    267 <pre>
    268     public void onActivityCreated(Bundle savedInstanceState) {
    269         super.onActivityCreated(savedInstanceState);
    270         ...
    271         // Gets the ListView from the View list of the parent activity
    272         mContactsList =
    273             (ListView) getActivity().findViewById(R.layout.contact_list_view);
    274         // Gets a CursorAdapter
    275         mCursorAdapter = new SimpleCursorAdapter(
    276                 getActivity(),
    277                 R.layout.contact_list_item,
    278                 null,
    279                 FROM_COLUMNS, TO_IDS,
    280                 0);
    281         // Sets the adapter for the ListView
    282         mContactsList.setAdapter(mCursorAdapter);
    283     }
    284 </pre>
    285 <h3 id="SetListener">Set the selected contact listener</h3>
    286 <p>
    287     When you display the results of a search, you usually want to allow the user to select a
    288     single contact for further processing. For example, when the user clicks a contact you can
    289     display the contact's address on a map. To provide this feature, you first defined the current
    290     {@link android.support.v4.app.Fragment} as the click listener by specifying that the class
    291     implements {@link android.widget.AdapterView.OnItemClickListener}, as shown in the section
    292     <a href="#Fragment">Define a Fragment that displays the list of contacts</a>.
    293 </p>
    294 <p>
    295     To continue setting up the listener, bind it to the {@link android.widget.ListView} by
    296     calling the method {@link android.widget.ListView#setOnItemClickListener
    297     setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
    298     onActivityCreated()}. For example:
    299 </p>
    300 <pre>
    301     public void onActivityCreated(Bundle savedInstanceState) {
    302         ...
    303         // Set the item click listener to be the current fragment.
    304         mContactsList.setOnItemClickListener(this);
    305         ...
    306     }
    307 </pre>
    308 <p>
    309     Since you specified that the current {@link android.support.v4.app.Fragment} is the
    310     {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} for the
    311     {@link android.widget.ListView}, you now need to implement its required method
    312     {@link android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()}, which
    313     handles the click event. This is described in a succeeding section.
    314 </p>
    315 <h3 id="DefineProjection">Define a projection</h3>
    316 <p>
    317     Define a constant that contains the columns you want to return from your query. Each item in
    318     the {@link android.widget.ListView} displays the contact's display name,
    319     which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
    320     the name of this column is
    321     {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
    322     Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
    323     {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
    324 </p>
    325 <p>
    326     The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
    327     {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
    328     {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
    329     {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
    330     construct a content URI for the contact the user selects.
    331 </p>
    332 <pre>
    333 ...
    334 &#64;SuppressLint("InlinedApi")
    335 private static final String[] PROJECTION =
    336         {
    337             Contacts._ID,
    338             Contacts.LOOKUP_KEY,
    339             Build.VERSION.SDK_INT
    340                     &gt;= Build.VERSION_CODES.HONEYCOMB ?
    341                     Contacts.DISPLAY_NAME_PRIMARY :
    342                     Contacts.DISPLAY_NAME
    343 
    344         };
    345 </pre>
    346 <h3 id="DefineConstants">Define constants for the Cursor column indexes</h3>
    347 <p>
    348     To get data from an individual column in a {@link android.database.Cursor}, you need
    349     the column's index within the {@link android.database.Cursor}. You can define constants
    350     for the indexes of the {@link android.database.Cursor} columns, because the indexes are
    351     the same as the order of the column names in your projection. For example:
    352 </p>
    353 <pre>
    354 // The column index for the _ID column
    355 private static final int CONTACT_ID_INDEX = 0;
    356 // The column index for the LOOKUP_KEY column
    357 private static final int LOOKUP_KEY_INDEX = 1;
    358 </pre>
    359 <h3 id="SelectionCriteria">Specify the selection criteria</h3>
    360 <p>
    361     To specify the data you want, create a combination of text expressions and variables
    362     that tell the provider the data columns to search and the values to find.
    363 </p>
    364 <p>
    365     For the text expression, define a constant that lists the search columns. Although this
    366     expression can contain values as well, the preferred practice is to represent the values with
    367     a "?" placeholder. During retrieval, the placeholder is replaced with values from an
    368     array. Using "?" as a placeholder ensures that the search specification is generated by binding
    369     rather than by SQL compilation. This practice eliminates the possibility of malicious SQL
    370     injection. For example:
    371 </p>
    372 <pre>
    373     // Defines the text expression
    374     &#64;SuppressLint("InlinedApi")
    375     private static final String SELECTION =
    376             Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
    377             Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
    378             Contacts.DISPLAY_NAME + " LIKE ?";
    379     // Defines a variable for the search string
    380     private String mSearchString;
    381     // Defines the array to hold values that replace the ?
    382     private String[] mSelectionArgs = { mSearchString };
    383 </pre>
    384 <h3 id="OnItemClick">Define the onItemClick() method</h3>
    385 <p>
    386     In a previous section, you set the item click listener for the {@link android.widget.ListView}.
    387     Now implement the action for the listener by defining the method
    388     {@link android.widget.AdapterView.OnItemClickListener#onItemClick
    389     AdapterView.OnItemClickListener.onItemClick()}:
    390 </p>
    391 <pre>
    392     &#64;Override
    393     public void onItemClick(
    394         AdapterView&lt;?&gt; parent, View item, int position, long rowID) {
    395         // Get the Cursor
    396         Cursor cursor = parent.getAdapter().getCursor();
    397         // Move to the selected contact
    398         cursor.moveToPosition(position);
    399         // Get the _ID value
    400         mContactId = getLong(CONTACT_ID_INDEX);
    401         // Get the selected LOOKUP KEY
    402         mContactKey = getString(CONTACT_KEY_INDEX);
    403         // Create the contact's content Uri
    404         mContactUri = Contacts.getLookupUri(mContactId, mContactKey);
    405         /*
    406          * You can use mContactUri as the content URI for retrieving
    407          * the details for a contact.
    408          */
    409     }
    410 </pre>
    411 <h3 id="InitializeLoader">Initialize the loader</h3>
    412 <p>
    413     Since you're using a {@link android.support.v4.content.CursorLoader} to retrieve data,
    414     you must initialize the background thread and other variables that control asynchronous
    415     retrieval. Do the initialization in
    416     {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, which
    417     is invoked immediately before the {@link android.support.v4.app.Fragment} UI appears, as
    418     shown in the following example:
    419 </p>
    420 <pre>
    421 public class ContactsFragment extends Fragment implements
    422         LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
    423     ...
    424     // Called just before the Fragment displays its UI
    425     &#64;Override
    426     public void onActivityCreated(Bundle savedInstanceState) {
    427         // Always call the super method first
    428         super.onActivityCreated(savedInstanceState);
    429         ...
    430         // Initializes the loader
    431         getLoaderManager().initLoader(0, null, this);
    432 </pre>
    433 <h3 id="OnCreateLoader">Implement onCreateLoader()</h3>
    434 <p>
    435     Implement the method
    436     {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
    437     which is called by the loader framework immediately after you call
    438     {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
    439 <p>
    440     In {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
    441     set up the search string pattern. To make a string into a pattern, insert "%"
    442     (percent) characters to represent a sequence of zero or more characters, or "_" (underscore)
    443     characters to represent a single character, or both. For example, the pattern "%Jefferson%"
    444     would match both "Thomas Jefferson" and "Jefferson Davis".
    445 </p>
    446 <p>
    447     Return a new {@link android.support.v4.content.CursorLoader} from the method. For the content
    448     URI, use {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}.
    449     This URI refers to the entire table, as shown in the following example:
    450 </p>
    451 <pre>
    452     ...
    453     &#64;Override
    454     public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
    455         /*
    456          * Makes search string into pattern and
    457          * stores it in the selection array
    458          */
    459         mSelectionArgs[0] = "%" + mSearchString + "%";
    460         // Starts the query
    461         return new CursorLoader(
    462                 getActivity(),
    463                 Contacts.CONTENT_URI,
    464                 PROJECTION,
    465                 SELECTION,
    466                 mSelectionArgs,
    467                 null
    468         );
    469     }
    470 </pre>
    471 <h3 id="FinishedReset">Implement onLoadFinished() and onLoaderReset()</h3>
    472 <p>
    473     Implement the
    474     {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    475     method. The loader framework calls
    476     {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
    477     when the Contacts Provider returns the results of the query. In this method, put the
    478     result {@link android.database.Cursor} in the
    479     {@link android.support.v4.widget.SimpleCursorAdapter}. This automatically updates the
    480     {@link android.widget.ListView} with the search results:
    481 </p>
    482 <pre>
    483     public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
    484         // Put the result Cursor in the adapter for the ListView
    485         mCursorAdapter.swapCursor(cursor);
    486     }
    487 </pre>
    488 <p>
    489     The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
    490     onLoaderReset()} is invoked when the loader framework detects that the
    491     result {@link android.database.Cursor} contains stale data. Delete the
    492     {@link android.support.v4.widget.SimpleCursorAdapter} reference to the existing
    493     {@link android.database.Cursor}. If you don't, the loader framework will not
    494     recycle the {@link android.database.Cursor}, which causes a memory leak. For example:
    495 </p>
    496 <pre>
    497     &#64;Override
    498     public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    499         // Delete the reference to the existing Cursor
    500         mCursorAdapter.swapCursor(null);
    501 
    502     }
    503 </pre>
    504 
    505 <p>
    506     You now have the key pieces of an app that matches a search string to contact names and returns
    507     the result in a {@link android.widget.ListView}. The user can click a contact name to select it.
    508     This triggers a listener, in which you can work further with the contact's data. For example,
    509     you can retrieve the contact's details. To learn how to do this, continue with the next
    510     lesson, <a href="#retrieve-details.html">Retrieving Details for a Contact</a>.
    511 </p>
    512 <p>
    513     To learn more about search user interfaces, read the API guide
    514     <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.
    515 </p>
    516 <p>
    517     The remaining sections in this lesson demonstrate other ways of finding contacts in the
    518     Contacts Provider.
    519 </p>
    520 <h2 id="TypeMatch">Match a Contact By a Specific Type of Data</h2>
    521 <p>
    522     This technique allows you to specify the type of data you want to match. Retrieving
    523     by name is a specific example of this type of query, but you can also do it for any of the types
    524     of detail data associated with a contact. For example, you can retrieve contacts that have a
    525     specific postal code; in this case, the search string has to match data stored in a postal code
    526     row.
    527 </p>
    528 <p>
    529     To implement this type of retrieval, first implement the following code, as listed in
    530     previous sections:
    531 </p>
    532 <ul>
    533     <li>
    534         Request Permission to Read the Provider.
    535     </li>
    536     <li>
    537         Define ListView and item layouts.
    538     </li>
    539     <li>
    540         Define a Fragment that displays the list of contacts.
    541     </li>
    542     <li>
    543         Define global variables.
    544     </li>
    545     <li>
    546         Initialize the Fragment.
    547     </li>
    548     <li>
    549         Set up the CursorAdapter for the ListView.
    550     </li>
    551     <li>
    552         Set the selected contact listener.
    553     </li>
    554     <li>
    555         Define constants for the Cursor column indexes.
    556         <p>
    557             Although you're retrieving data from a different table, the order of the columns in
    558             the projection is the same, so you can use the same indexes for the Cursor.
    559         </p>
    560     </li>
    561     <li>
    562         Define the onItemClick() method.
    563     </li>
    564     <li>
    565         Initialize the loader.
    566     </li>
    567     <li>
    568 
    569         Implement onLoadFinished() and onLoaderReset().
    570     </li>
    571 </ul>
    572 <p>
    573     The following steps show you the additional code you need to match a search string to
    574     a particular type of detail data and display the results.
    575 </p>
    576 <h3>Choose the data type and table</h3>
    577 <p>
    578     To search for a particular type of detail data, you have to know the custom MIME type value
    579     for the data type. Each data type has a unique MIME type
    580     value defined by a constant <code>CONTENT_ITEM_TYPE</code> in the subclass of
    581     {@link android.provider.ContactsContract.CommonDataKinds} associated with the data type.
    582     The subclasses have names that indicate their data type; for example, the subclass for email
    583     data is {@link android.provider.ContactsContract.CommonDataKinds.Email}, and the custom MIME
    584     type for email data is defined by the constant
    585     {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    586     Email.CONTENT_ITEM_TYPE}.
    587 </p>
    588 <p>
    589     Use the {@link android.provider.ContactsContract.Data} table for your search. All of the
    590     constants you need for your projection, selection clause, and sort order are defined in or
    591     inherited by this table.
    592 </p>
    593 <h3 id="SpecificProjection">Define a projection</h3>
    594 <p>
    595     To define a projection, choose one or more of the columns defined in
    596     {@link android.provider.ContactsContract.Data} or the classes from which it inherits. The
    597     Contacts Provider does an implicit join between {@link android.provider.ContactsContract.Data}
    598     and other tables before it returns rows. For example:
    599 </p>
    600 <pre>
    601     &#64;SuppressLint("InlinedApi")
    602     private static final String[] PROJECTION =
    603         {
    604             /*
    605              * The detail data row ID. To make a ListView work,
    606              * this column is required.
    607              */
    608             Data._ID,
    609             // The primary display name
    610             Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
    611                     Data.DISPLAY_NAME_PRIMARY :
    612                     Data.DISPLAY_NAME,
    613             // The contact's _ID, to construct a content URI
    614             Data.CONTACT_ID
    615             // The contact's LOOKUP_KEY, to construct a content URI
    616             Data.LOOKUP_KEY (a permanent link to the contact
    617         };
    618 </pre>
    619 <h3 id="SpecificCriteria">Define search criteria</h3>
    620 <p>
    621     To search for a string within a particular type of data, construct a selection clause from
    622     the following:
    623 </p>
    624 <ul>
    625     <li>
    626         The name of the column that contains your search string. This name varies by data type,
    627         so you need to find the subclass of
    628         {@link android.provider.ContactsContract.CommonDataKinds} that corresponds to the data type
    629         and then choose the column name from that subclass. For example, to search for
    630         email addresses, use the column
    631         {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS Email.ADDRESS}.
    632     </li>
    633     <li>
    634         The search string itself, represented as the "?" character in the selection clause.
    635     </li>
    636     <li>
    637         The name of the column that contains the custom MIME type value. This name is always
    638         {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
    639     </li>
    640     <li>
    641         The custom MIME type value for the data type. As described previously, this is the constant
    642         <code>CONTENT_ITEM_TYPE</code> in the
    643         {@link android.provider.ContactsContract.CommonDataKinds} subclass. For example, the MIME
    644         type value for email data is
    645         {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
    646         Email.CONTENT_ITEM_TYPE}. Enclose the value in single quotes by concatenating a
    647         "<code>'</code>" (single quote) character to the start and end of the constant; otherwise,
    648         the provider interprets the value as a variable name rather than as a string value.
    649         You don't need to use a placeholder for this value, because you're using a constant
    650         rather than a user-supplied value.
    651     </li>
    652 </ul>
    653 <p>
    654     For example:
    655 </p>
    656 <pre>
    657     /*
    658      * Constructs search criteria from the search string
    659      * and email MIME type
    660      */
    661     private static final String SELECTION =
    662             /*
    663              * Searches for an email address
    664              * that matches the search string
    665              */
    666             Email.ADDRESS + " LIKE ? " + "AND " +
    667             /*
    668              * Searches for a MIME type that matches
    669              * the value of the constant
    670              * Email.CONTENT_ITEM_TYPE. Note the
    671              * single quotes surrounding Email.CONTENT_ITEM_TYPE.
    672              */
    673             Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
    674 </pre>
    675 <p>
    676     Next, define variables to contain the selection argument:
    677 </p>
    678 <pre>
    679     String mSearchString;
    680     String[] mSelectionArgs = { "" };
    681 </pre>
    682 <h3 id="SpecificLoader">Implement onCreateLoader()</h3>
    683 <p>
    684     Now that you've specified the data you want and how to find it, define a query in your
    685     implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
    686     onCreateLoader()}. Return a new {@link android.support.v4.content.CursorLoader} from this
    687     method, using your projection, selection text expression, and selection array as
    688     arguments. For a content URI, use
    689     {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI}. For example:
    690 </p>
    691 <pre>
    692     &#64;Override
    693     public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
    694         // OPTIONAL: Makes search string into pattern
    695         mSearchString = "%" + mSearchString + "%";
    696         // Puts the search string into the selection criteria
    697         mSelectionArgs[0] = mSearchString;
    698         // Starts the query
    699         return new CursorLoader(
    700                 getActivity(),
    701                 Data.CONTENT_URI,
    702                 PROJECTION,
    703                 SELECTION,
    704                 mSelectionArgs,
    705                 null
    706         );
    707     }
    708 </pre>
    709 <p>
    710     These code snippets are the basis of a simple reverse lookup based on a specific type of detail
    711     data. This is the best technique to use if your app focuses on a particular type of data, such
    712     as emails, and you want allow users to get the names associated with a piece of data.
    713 </p>
    714 <h2 id="GeneralMatch">Match a Contact By Any Type of Data</h2>
    715 <p>
    716     Retrieving a contact based on any type of data returns contacts if any of their data matches a
    717     the search string, including name, email address, postal address, phone number, and so forth.
    718     This results in a broad set of search results. For example, if the search string
    719     is "Doe", then searching for any data type returns the contact "John Doe"; it also returns
    720     contacts who live on "Doe Street".
    721 </p>
    722 <p>
    723     To implement this type of retrieval, first implement the following code, as listed in
    724     previous sections:
    725 </p>
    726 <ul>
    727     <li>
    728         Request Permission to Read the Provider.
    729     </li>
    730     <li>
    731         Define ListView and item layouts.
    732     </li>
    733     <li>
    734     <li>
    735         Define a Fragment that displays the list of contacts.
    736     </li>
    737     <li>
    738         Define global variables.
    739     </li>
    740     <li>
    741         Initialize the Fragment.
    742     </li>
    743     <li>
    744         Set up the CursorAdapter for the ListView.
    745     </li>
    746     <li>
    747         Set the selected contact listener.
    748     </li>
    749     <li>
    750         Define a projection.
    751     </li>
    752     <li>
    753         Define constants for the Cursor column indexes.
    754         <p>
    755             For this type of retrieval, you're using the same table you used in the section
    756             <a href="#NameMatch">Match a Contact by Name and List the Results</a>. Use the
    757             same column indexes as well.
    758         </p>
    759     </li>
    760     <li>
    761         Define the onItemClick() method.
    762     </li>
    763     <li>
    764         Initialize the loader.
    765     </li>
    766     <li>
    767 
    768         Implement onLoadFinished() and onLoaderReset().
    769     </li>
    770 </ul>
    771 <p>
    772     The following steps show you the additional code you need to match a search string to
    773     any type of data and display the results.
    774 </p>
    775 <h3 id="NoSelection">Remove selection criteria</h3>
    776 <p>
    777     Don't define the <code>SELECTION</code> constants or the <code>mSelectionArgs</code> variable.
    778     These aren't used in this type of retrieval.
    779 </p>
    780 <h3 id="CreateLoaderAny">Implement onCreateLoader()</h3>
    781 <p>
    782     Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
    783     onCreateLoader()} method, returning a new {@link android.support.v4.content.CursorLoader}.
    784     You don't need to convert the search string into a pattern, because the Contacts Provider does
    785     that automatically. Use
    786     {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI
    787     Contacts.CONTENT_FILTER_URI} as the base URI, and append your search string to it by calling
    788     {@link android.net.Uri#withAppendedPath Uri.withAppendedPath()}. Using this URI
    789     automatically triggers searching for any data type, as shown in the following example:
    790 </p>
    791 <pre>
    792     &#64;Override
    793     public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
    794         /*
    795          * Appends the search string to the base URI. Always
    796          * encode search strings to ensure they're in proper
    797          * format.
    798          */
    799         Uri contentUri = Uri.withAppendedPath(
    800                 Contacts.CONTENT_FILTER_URI,
    801                 Uri.encode(mSearchString));
    802         // Starts the query
    803         return new CursorLoader(
    804                 getActivity(),
    805                 contentUri,
    806                 PROJECTION,
    807                 null,
    808                 null,
    809                 null
    810         );
    811     }
    812 </pre>
    813 <p>
    814     These code snippets are the basis of an app that does a broad search of the Contacts Provider.
    815     The technique is useful for apps that want to implement functionality similar to the
    816     People app's contact list screen.
    817 </p>
    818