• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Retrieving a List of Contacts
2
3trainingnavtop=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 can define
106    the main layout file <code>res/layout/contacts_list_view.xml</code> that contains the
107    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>
170import 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...
181import android.support.v4.app.Fragment;
182import android.support.v4.app.LoaderManager.LoaderCallbacks;
183import android.widget.AdapterView;
184...
185public 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.contacts_list_layout, container, false);
254    }
255</pre>
256<h3 id="DefineAdapter">Set up the CursorAdapter for the ListView</h3>
257<p>
258    Set up the {@link android.support.v4.widget.SimpleCursorAdapter} that binds the results of the
259    search to the {@link android.widget.ListView}. To get the {@link android.widget.ListView} object
260    that displays the contacts, you need to call {@link android.app.Activity#findViewById
261    Activity.findViewById()} using the parent activity of the
262    {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
263    parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
264    For example:
265</p>
266<pre>
267    public void onActivityCreated(Bundle savedInstanceState) {
268        super.onActivityCreated(savedInstanceState);
269        ...
270        // Gets the ListView from the View list of the parent activity
271        mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view);
272        // Gets a CursorAdapter
273        mCursorAdapter = new SimpleCursorAdapter(
274                getActivity(),
275                R.layout.contact_list_item,
276                null,
277                FROM_COLUMNS, TO_IDS,
278                0);
279        // Sets the adapter for the ListView
280        mContactsList.setAdapter(mCursorAdapter);
281    }
282</pre>
283<h3 id="SetListener">Set the selected contact listener</h3>
284<p>
285    When you display the results of a search, you usually want to allow the user to select a
286    single contact for further processing. For example, when the user clicks a contact you can
287    display the contact's address on a map. To provide this feature, you first defined the current
288    {@link android.support.v4.app.Fragment} as the click listener by specifying that the class
289    implements {@link android.widget.AdapterView.OnItemClickListener}, as shown in the section
290    <a href="#Fragment">Define a Fragment that displays the list of contacts</a>.
291</p>
292<p>
293    To continue setting up the listener, bind it to the {@link android.widget.ListView} by
294    calling the method {@link android.widget.ListView#setOnItemClickListener
295    setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
296    onActivityCreated()}. For example:
297</p>
298<pre>
299    public void onActivityCreated(Bundle savedInstanceState) {
300        ...
301        // Set the item click listener to be the current fragment.
302        mContactsList.setOnItemClickListener(this);
303        ...
304    }
305</pre>
306<p>
307    Since you specified that the current {@link android.support.v4.app.Fragment} is the
308    {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} for the
309    {@link android.widget.ListView}, you now need to implement its required method
310    {@link android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()}, which
311    handles the click event. This is described in a succeeding section.
312</p>
313<h3 id="DefineProjection">Define a projection</h3>
314<p>
315    Define a constant that contains the columns you want to return from your query. Each item in
316    the {@link android.widget.ListView} displays the contact's display name,
317    which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
318    the name of this column is
319    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
320    Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
321    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
322</p>
323<p>
324    The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
325    {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
326    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
327    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
328    construct a content URI for the contact the user selects.
329</p>
330<pre>
331...
332&#64;SuppressLint("InlinedApi")
333private static final String[] PROJECTION =
334        {
335            Contacts._ID,
336            Contacts.LOOKUP_KEY,
337            Build.VERSION.SDK_INT
338                    &gt;= Build.VERSION_CODES.HONEYCOMB ?
339                    Contacts.DISPLAY_NAME_PRIMARY :
340                    Contacts.DISPLAY_NAME
341
342        };
343</pre>
344<h3 id="DefineConstants">Define constants for the Cursor column indexes</h3>
345<p>
346    To get data from an individual column in a {@link android.database.Cursor}, you need
347    the column's index within the {@link android.database.Cursor}. You can define constants
348    for the indexes of the {@link android.database.Cursor} columns, because the indexes are
349    the same as the order of the column names in your projection. For example:
350</p>
351<pre>
352// The column index for the _ID column
353private static final int CONTACT_ID_INDEX = 0;
354// The column index for the LOOKUP_KEY column
355private static final int LOOKUP_KEY_INDEX = 1;
356</pre>
357<h3 id="SelectionCriteria">Specify the selection criteria</h3>
358<p>
359    To specify the data you want, create a combination of text expressions and variables
360    that tell the provider the data columns to search and the values to find.
361</p>
362<p>
363    For the text expression, define a constant that lists the search columns. Although this
364    expression can contain values as well, the preferred practice is to represent the values with
365    a "?" placeholder. During retrieval, the placeholder is replaced with values from an
366    array. Using "?" as a placeholder ensures that the search specification is generated by binding
367    rather than by SQL compilation. This practice eliminates the possibility of malicious SQL
368    injection. For example:
369</p>
370<pre>
371    // Defines the text expression
372    &#64;SuppressLint("InlinedApi")
373    private static final String SELECTION =
374            Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
375            Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
376            Contacts.DISPLAY_NAME + " LIKE ?";
377    // Defines a variable for the search string
378    private String mSearchString;
379    // Defines the array to hold values that replace the ?
380    private String[] mSelectionArgs = { mSearchString };
381</pre>
382<h3 id="OnItemClick">Define the onItemClick() method</h3>
383<p>
384    In a previous section, you set the item click listener for the {@link android.widget.ListView}.
385    Now implement the action for the listener by defining the method
386    {@link android.widget.AdapterView.OnItemClickListener#onItemClick
387    AdapterView.OnItemClickListener.onItemClick()}:
388</p>
389<pre>
390    &#64;Override
391    public void onItemClick(
392        AdapterView&lt;?&gt; parent, View item, int position, long rowID) {
393        // Get the Cursor
394        Cursor cursor = parent.getAdapter().getCursor();
395        // Move to the selected contact
396        cursor.moveToPosition(position);
397        // Get the _ID value
398        mContactId = getLong(CONTACT_ID_INDEX);
399        // Get the selected LOOKUP KEY
400        mContactKey = getString(CONTACT_KEY_INDEX);
401        // Create the contact's content Uri
402        mContactUri = Contacts.getLookupUri(mContactId, mContactKey);
403        /*
404         * You can use mContactUri as the content URI for retrieving
405         * the details for a contact.
406         */
407    }
408</pre>
409<h3 id="InitializeLoader">Initialize the loader</h3>
410<p>
411    Since you're using a {@link android.support.v4.content.CursorLoader} to retrieve data,
412    you must initialize the background thread and other variables that control asynchronous
413    retrieval. Do the initialization in
414    {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, which
415    is invoked immediately before the {@link android.support.v4.app.Fragment} UI appears, as
416    shown in the following example:
417</p>
418<pre>
419public class ContactsFragment extends Fragment implements
420        LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
421    ...
422    // Called just before the Fragment displays its UI
423    &#64;Override
424    public void onActivityCreated(Bundle savedInstanceState) {
425        // Always call the super method first
426        super.onActivityCreated(savedInstanceState);
427        ...
428        // Initializes the loader
429        getLoaderManager().initLoader(0, null, this);
430</pre>
431<h3 id="OnCreateLoader">Implement onCreateLoader()</h3>
432<p>
433    Implement the method
434    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
435    which is called by the loader framework immediately after you call
436    {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
437<p>
438    In {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
439    set up the search string pattern. To make a string into a pattern, insert "%"
440    (percent) characters to represent a sequence of zero or more characters, or "_" (underscore)
441    characters to represent a single character, or both. For example, the pattern "%Jefferson%"
442    would match both "Thomas Jefferson" and "Jefferson Davis".
443</p>
444<p>
445    Return a new {@link android.support.v4.content.CursorLoader} from the method. For the content
446    URI, use {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}.
447    This URI refers to the entire table, as shown in the following example:
448</p>
449<pre>
450    ...
451    &#64;Override
452    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
453        /*
454         * Makes search string into pattern and
455         * stores it in the selection array
456         */
457        mSelectionArgs[0] = "%" + mSearchString + "%";
458        // Starts the query
459        return new CursorLoader(
460                getActivity(),
461                Contacts.CONTENT_URI,
462                PROJECTION,
463                SELECTION,
464                mSelectionArgs,
465                null
466        );
467    }
468</pre>
469<h3 id="FinishedReset">Implement onLoadFinished() and onLoaderReset()</h3>
470<p>
471    Implement the
472    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
473    method. The loader framework calls
474    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
475    when the Contacts Provider returns the results of the query. In this method, put the
476    result {@link android.database.Cursor} in the
477    {@link android.support.v4.widget.SimpleCursorAdapter}. This automatically updates the
478    {@link android.widget.ListView} with the search results:
479</p>
480<pre>
481    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
482        // Put the result Cursor in the adapter for the ListView
483        mCursorAdapter.swapCursor(cursor);
484    }
485</pre>
486<p>
487    The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
488    onLoaderReset()} is invoked when the loader framework detects that the
489    result {@link android.database.Cursor} contains stale data. Delete the
490    {@link android.support.v4.widget.SimpleCursorAdapter} reference to the existing
491    {@link android.database.Cursor}. If you don't, the loader framework will not
492    recycle the {@link android.database.Cursor}, which causes a memory leak. For example:
493</p>
494<pre>
495    &#64;Override
496    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
497        // Delete the reference to the existing Cursor
498        mCursorAdapter.swapCursor(null);
499
500    }
501</pre>
502
503<p>
504    You now have the key pieces of an app that matches a search string to contact names and returns
505    the result in a {@link android.widget.ListView}. The user can click a contact name to select it.
506    This triggers a listener, in which you can work further with the contact's data. For example,
507    you can retrieve the contact's details. To learn how to do this, continue with the next
508    lesson, <a href="#retrieve-details.html">Retrieving Details for a Contact</a>.
509</p>
510<p>
511    To learn more about search user interfaces, read the API guide
512    <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.
513</p>
514<p>
515    The remaining sections in this lesson demonstrate other ways of finding contacts in the
516    Contacts Provider.
517</p>
518<h2 id="TypeMatch">Match a Contact By a Specific Type of Data</h2>
519<p>
520    This technique allows you to specify the type of data you want to match. Retrieving
521    by name is a specific example of this type of query, but you can also do it for any of the types
522    of detail data associated with a contact. For example, you can retrieve contacts that have a
523    specific postal code; in this case, the search string has to match data stored in a postal code
524    row.
525</p>
526<p>
527    To implement this type of retrieval, first implement the following code, as listed in
528    previous sections:
529</p>
530<ul>
531    <li>
532        Request Permission to Read the Provider.
533    </li>
534    <li>
535        Define ListView and item layouts.
536    </li>
537    <li>
538        Define a Fragment that displays the list of contacts.
539    </li>
540    <li>
541        Define global variables.
542    </li>
543    <li>
544        Initialize the Fragment.
545    </li>
546    <li>
547        Set up the CursorAdapter for the ListView.
548    </li>
549    <li>
550        Set the selected contact listener.
551    </li>
552    <li>
553        Define constants for the Cursor column indexes.
554        <p>
555            Although you're retrieving data from a different table, the order of the columns in
556            the projection is the same, so you can use the same indexes for the Cursor.
557        </p>
558    </li>
559    <li>
560        Define the onItemClick() method.
561    </li>
562    <li>
563        Initialize the loader.
564    </li>
565    <li>
566
567        Implement onLoadFinished() and onLoaderReset().
568    </li>
569</ul>
570<p>
571    The following steps show you the additional code you need to match a search string to
572    a particular type of detail data and display the results.
573</p>
574<h3>Choose the data type and table</h3>
575<p>
576    To search for a particular type of detail data, you have to know the custom MIME type value
577    for the data type. Each data type has a unique MIME type
578    value defined by a constant <code>CONTENT_ITEM_TYPE</code> in the subclass of
579    {@link android.provider.ContactsContract.CommonDataKinds} associated with the data type.
580    The subclasses have names that indicate their data type; for example, the subclass for email
581    data is {@link android.provider.ContactsContract.CommonDataKinds.Email}, and the custom MIME
582    type for email data is defined by the constant
583    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
584    Email.CONTENT_ITEM_TYPE}.
585</p>
586<p>
587    Use the {@link android.provider.ContactsContract.Data} table for your search. All of the
588    constants you need for your projection, selection clause, and sort order are defined in or
589    inherited by this table.
590</p>
591<h3 id="SpecificProjection">Define a projection</h3>
592<p>
593    To define a projection, choose one or more of the columns defined in
594    {@link android.provider.ContactsContract.Data} or the classes from which it inherits. The
595    Contacts Provider does an implicit join between {@link android.provider.ContactsContract.Data}
596    and other tables before it returns rows. For example:
597</p>
598<pre>
599    &#64;SuppressLint("InlinedApi")
600    private static final String[] PROJECTION =
601        {
602            /*
603             * The detail data row ID. To make a ListView work,
604             * this column is required.
605             */
606            Data._ID,
607            // The primary display name
608            Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
609                    Data.DISPLAY_NAME_PRIMARY :
610                    Data.DISPLAY_NAME,
611            // The contact's _ID, to construct a content URI
612            Data.CONTACT_ID
613            // The contact's LOOKUP_KEY, to construct a content URI
614            Data.LOOKUP_KEY (a permanent link to the contact
615        };
616</pre>
617<h3 id="SpecificCriteria">Define search criteria</h3>
618<p>
619    To search for a string within a particular type of data, construct a selection clause from
620    the following:
621</p>
622<ul>
623    <li>
624        The name of the column that contains your search string. This name varies by data type,
625        so you need to find the subclass of
626        {@link android.provider.ContactsContract.CommonDataKinds} that corresponds to the data type
627        and then choose the column name from that subclass. For example, to search for
628        email addresses, use the column
629        {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS Email.ADDRESS}.
630    </li>
631    <li>
632        The search string itself, represented as the "?" character in the selection clause.
633    </li>
634    <li>
635        The name of the column that contains the custom MIME type value. This name is always
636        {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
637    </li>
638    <li>
639        The custom MIME type value for the data type. As described previously, this is the constant
640        <code>CONTENT_ITEM_TYPE</code> in the
641        {@link android.provider.ContactsContract.CommonDataKinds} subclass. For example, the MIME
642        type value for email data is
643        {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
644        Email.CONTENT_ITEM_TYPE}. Enclose the value in single quotes by concatenating a
645        "<code>'</code>" (single quote) character to the start and end of the constant; otherwise,
646        the provider interprets the value as a variable name rather than as a string value.
647        You don't need to use a placeholder for this value, because you're using a constant
648        rather than a user-supplied value.
649    </li>
650</ul>
651<p>
652    For example:
653</p>
654<pre>
655    /*
656     * Constructs search criteria from the search string
657     * and email MIME type
658     */
659    private static final String SELECTION =
660            /*
661             * Searches for an email address
662             * that matches the search string
663             */
664            Email.ADDRESS + " LIKE ? " + "AND " +
665            /*
666             * Searches for a MIME type that matches
667             * the value of the constant
668             * Email.CONTENT_ITEM_TYPE. Note the
669             * single quotes surrounding Email.CONTENT_ITEM_TYPE.
670             */
671            Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
672</pre>
673<p>
674    Next, define variables to contain the selection argument:
675</p>
676<pre>
677    String mSearchString;
678    String[] mSelectionArgs = { "" };
679</pre>
680<h3 id="SpecificLoader">Implement onCreateLoader()</h3>
681<p>
682    Now that you've specified the data you want and how to find it, define a query in your
683    implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
684    onCreateLoader()}. Return a new {@link android.support.v4.content.CursorLoader} from this
685    method, using your projection, selection text expression, and selection array as
686    arguments. For a content URI, use
687    {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI}. For example:
688</p>
689<pre>
690    &#64;Override
691    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
692        // OPTIONAL: Makes search string into pattern
693        mSearchString = "%" + mSearchString + "%";
694        // Puts the search string into the selection criteria
695        mSelectionArgs[0] = mSearchString;
696        // Starts the query
697        return new CursorLoader(
698                getActivity(),
699                Data.CONTENT_URI,
700                PROJECTION,
701                SELECTION,
702                mSelectionArgs,
703                null
704        );
705    }
706</pre>
707<p>
708    These code snippets are the basis of a simple reverse lookup based on a specific type of detail
709    data. This is the best technique to use if your app focuses on a particular type of data, such
710    as emails, and you want allow users to get the names associated with a piece of data.
711</p>
712<h2 id="GeneralMatch">Match a Contact By Any Type of Data</h2>
713<p>
714    Retrieving a contact based on any type of data returns contacts if any of their data matches a
715    the search string, including name, email address, postal address, phone number, and so forth.
716    This results in a broad set of search results. For example, if the search string
717    is "Doe", then searching for any data type returns the contact "John Doe"; it also returns
718    contacts who live on "Doe Street".
719</p>
720<p>
721    To implement this type of retrieval, first implement the following code, as listed in
722    previous sections:
723</p>
724<ul>
725    <li>
726        Request Permission to Read the Provider.
727    </li>
728    <li>
729        Define ListView and item layouts.
730    </li>
731    <li>
732    <li>
733        Define a Fragment that displays the list of contacts.
734    </li>
735    <li>
736        Define global variables.
737    </li>
738    <li>
739        Initialize the Fragment.
740    </li>
741    <li>
742        Set up the CursorAdapter for the ListView.
743    </li>
744    <li>
745        Set the selected contact listener.
746    </li>
747    <li>
748        Define a projection.
749    </li>
750    <li>
751        Define constants for the Cursor column indexes.
752        <p>
753            For this type of retrieval, you're using the same table you used in the section
754            <a href="#NameMatch">Match a Contact by Name and List the Results</a>. Use the
755            same column indexes as well.
756        </p>
757    </li>
758    <li>
759        Define the onItemClick() method.
760    </li>
761    <li>
762        Initialize the loader.
763    </li>
764    <li>
765
766        Implement onLoadFinished() and onLoaderReset().
767    </li>
768</ul>
769<p>
770    The following steps show you the additional code you need to match a search string to
771    any type of data and display the results.
772</p>
773<h3 id="NoSelection">Remove selection criteria</h3>
774<p>
775    Don't define the <code>SELECTION</code> constants or the <code>mSelectionArgs</code> variable.
776    These aren't used in this type of retrieval.
777</p>
778<h3 id="CreateLoaderAny">Implement onCreateLoader()</h3>
779<p>
780    Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
781    onCreateLoader()} method, returning a new {@link android.support.v4.content.CursorLoader}.
782    You don't need to convert the search string into a pattern, because the Contacts Provider does
783    that automatically. Use
784    {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI
785    Contacts.CONTENT_FILTER_URI} as the base URI, and append your search string to it by calling
786    {@link android.net.Uri#withAppendedPath Uri.withAppendedPath()}. Using this URI
787    automatically triggers searching for any data type, as shown in the following example:
788</p>
789<pre>
790    &#64;Override
791    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
792        /*
793         * Appends the search string to the base URI. Always
794         * encode search strings to ensure they're in proper
795         * format.
796         */
797        Uri contentUri = Uri.withAppendedPath(
798                Contacts.CONTENT_FILTER_URI,
799                Uri.encode(mSearchString));
800        // Starts the query
801        return new CursorLoader(
802                getActivity(),
803                contentUri,
804                PROJECTION,
805                null,
806                null,
807                null
808        );
809    }
810</pre>
811<p>
812    These code snippets are the basis of an app that does a broad search of the Contacts Provider.
813    The technique is useful for apps that want to implement functionality similar to the
814    People app's contact list screen.
815</p>
816