2011年5月16日月曜日

AndroidStudyMemo=Using the Contacts Content Provider

The Contacts database is one of the most commonly used applications on the mobile

phone. People always want phone numbers handy for calling friends, family, coworkers,

and clients.Additionally, most phones show the identity of the caller based on the contacts

application, including nicknames, photos, or icons.

Android provides a built-in Contact application, and the contact data is exposed to

other Android applications using the content provider interface.As an application developer,

this means you can leverage the user's contact data within your application for a

more robust user experience.

 

Accessing Private Contact Data

Your application needs special permission to access the private user information provided

by the Contacts content provider.You must declare a uses-permission tag using the

permission READ_CONTACTS to read this information.

 

The code to start reading contact data from the Contacts application should look familiar.

Cursor oneContact = managedQuery( People.CONTENT_URI, null, null, null,

"name desc LIMIT 1");

Log.d(debugTag, "Count: " + oneContact.getCount());

 

This short example simply shows querying for a single contact.We used LIMIT to retrieve

one contact record. If you actually look at the returned columns of data, you find

that there is little more than the contact name and some indexes.The data fields are not

explicitly returned. Instead, the results include the values needed to build specific URIs to

those pieces of data.We need to request the data for the contact using these indexes.

Specifically,we retrieve the primary email and primary phone number for this contact.

 

int nameIdx = oneContact.getColumnIndex(Contacts.People.NAME);

int emailIDIdx = oneContact

.getColumnIndex(Contacts.People.PRIMARY_EMAIL_ID);

int phoneIDIdx = oneContact

.getColumnIndex(Contacts.People.PRIMARY_PHONE_ID);

oneContact.moveToFirst();

int emailID = oneContact.getInt(emailIDIdx);

int phoneID = oneContact.getInt(phoneIDIdx);

 

Now that we have the column index values for the contact's name, primary email address,

and primary phone number,we need to build the Uri objects associated with those pieces

of information and query for the primary email and primary phone number.

Uri emailUri = ContentUris.withAppendedId(

Contacts.ContactMethods.CONTENT_URI,

emailID);

Uri phoneUri = ContentUris.withAppendedId(

Contacts.Phones.CONTENT_URI, phoneID);

Cursor primaryEmail = managedQuery(emailUri,

new String[] {

Contacts.ContactMethods.DATA

},

null, null, null);

Cursor primaryNumber = managedQuery(phoneUri,

new String[] {

Contacts.Phones.NUMBER

},

null, null, null);

 

After retrieving the appropriate column indexes for a contact's specific email and

phone number,we call ContentUris.withAppendedId() to create the new Uri objects

from existing ones and the identifiers we now have.This enables direct selection of a particular

row from the table when the index of that row is known.You can use a selection

parameter to do this, as well. Lastly,we used the two new Uri objects to perform two calls

to managedQuery().

 

Now we take a shortcut with the requested columns String array because each query

only has one column:

String name = oneContact.getString(nameIdx);

primaryEmail.moveToFirst();

String email = primaryEmail.getString(0);

primaryNumber.moveToFirst();

String number = primaryNumber.getString(0);

 

If an email or phone number doesn't exist, an exception called

android.database.CursorIndexOutOfBoundsException is thrown.This can be caught,

or you can check to see that a result was actually returned in the Cursor first.

Querying for a Specific Contact

If that seemed like quite a lot of coding to get a phone number, you're not alone. For getting

a quick piece of data, there is a faster way.The following block of code demonstrates

how we can get the primary number and name for one contact.The primary number for

a contact is designated as the default number within the contact manager on the handset.

It might be useful to use the primary number field if you don't get any results back from

the query.

String[] requestedColumns = {

Contacts.Phones.NAME,

Contacts.Phones.NUMBER,

};

Cursor contacts = managedQuery(

Contacts.Phones.CONTENT_URI,

requestedColumns,

Contacts.Phones.ISPRIMARY + "<>0",

null, "name desc limit 1");

Log.d(debugTag, "Contacts count: "

+ contacts.getCount());

int nameIdx = contacts

.getColumnIndex(Contacts.Phones.NAME);

int phoneIdx = contacts

.getColumnIndex(Contacts.Phones.NUMBER);

contacts.moveToFirst();

Log.d(debugTag, "Name: " + contacts.getString(nameIdx));

Log.d(debugTag, "Phone: " + contacts.getString(phoneIdx));

 

This block of code should look somewhat familiar, yet it is a much shorter and more

straightforward method to query for phone numbers by Contact name.The

Contacts.Phones.CONTENT_URI contains phone numbers but it also happens to have the

contact name.This is similar to the CallLog content provider.

 

 

Modifying Content Providers Data

Content providers are not only static sources of data.They can also be used to add, update,

and delete data, if the content provider application has implemented this functionality.

Your application must have the appropriate permissions (that is, WRITE_CONTACTS as opposed

to READ_CONTACTS) to perform some of these actions.

Adding Records

Using the Contacts content provider,we can, for example, add a new record to the contacts

database programmatically.

 

ContentValues values = new ContentValues();

values.put(Contacts.People.NAME, "Sample User");

Uri uri = getContentResolver().insert(

Contacts.People.CONTENT_URI, values);

Uri phoneUri = Uri.withAppendedPath(uri,

Contacts.People.Phones.CONTENT_DIRECTORY);

 

values.clear();

values.put(Contacts.Phones.NUMBER, "2125551212");

values.put(Contacts.Phones.TYPE, Contacts.Phones.TYPE_WORK);

getContentResolver().insert(phoneUri, values);

 

values.clear();

values.put(Contacts.Phones.NUMBER, "3135551212");

values.put(Contacts.Phones.TYPE, Contacts.Phones.TYPE_MOBILE);

getContentResolver().insert(phoneUri, values);

 

Just as we used the ContentValues class to insert records into an application's SQLite

database,we use it again here.The first action we take is to provide a name for the

Contacts.People.NAME column.We need to create the contact with a name before we

can assign information, such as phone numbers.Think of this as creating a row in a table

that provides a one-to-many relationship to a phone number table.

 

Next,we insert the data in the database found at the Contacts.People.CONTENT_URI

path.We use a call to getContentResolver() to retrieve the ContentResolver associated

with our Activity.The return value is the Uri of our new contact.We need to use it for

adding phone numbers to our new contact.We then reuse the ContentValues instance by

clearing it and adding a Contacts.Phones.NUMBER and the Contacts.Phones.TYPE for it.

Using the ContentResolver,we insert this data into the newly created Uri.

 

 

Updating Records

Inserting data isn't the only change you can make.You can update one or more rows, as

well.The following block of code shows how to update data within a content provider. In

this case,we update a note field for a specific contact, using its unique identifier.

 

ContentValues values = new ContentValues();

values.put(People.NOTES, "This is my boss");

Uri updateUri = ContentUris.withAppendedId(People.CONTENT_URI, rowId);

int rows = getContentResolver().update(updateUri, values, null, null);

Log.d(debugTag, "Rows updated: " + rows);

 

Again,we use an instance of the ContentValues object to map the data field we want to

update with the data value?in this case, the note field.This replaces any current note

stored in the NOTES field currently stored with the contact.We then create the Uri for the

specific contact we are updating.A simple call to the update() method of the

ContentResolver class completes our change.We can then confirm that only one row

was updated.

 

Deleting Records

Now that you cluttered up your contacts application with sample user data, you might

want to delete some of it. Deleting data is fairly straightforward.

Deleting All Records

The following code deletes all rows at the given URI, although you should execute operations

like this with extreme care:

 

int rows = getContentResolver().delete(People.CONTENT_URI, null, null);

Log.d(debugTag, "Rows: "+ rows);

 

The delete() method deletes all rows at a given URI filtered by the selection parameters,

which, in this case, includes all rows at the People.CONTENT_URI location; in other

words, all contact entries.

 

Deleting Specific Records

Often you want to select specific rows to delete by adding the unique identifier index to

the end of the URI or remove rows matching a particular pattern.

For example, the following deletion matches all contact records with the name Sample

User, which we used when we created sample contacts previously in the chapter.

 

int rows = getContentResolver().delete(People.CONTENT_URI,

People.NAME + "=?",

new String[] {"Sample User"});

Log.d(debugTag, "Rows: "+ rows);

 

 

0 件のコメント:

コメントを投稿