2011年5月16日月曜日

AndroidStudyMemo=Sharing Data Between Applications with Content Providers

Locating Content on the Android System Using URIs

 

Most access to content providers comes in the form of queries: a list of contacts, a list of

bookmarks, a list of calls, a list of pictures, and a list of audio files.Applications make these

requests much as they would access a database, and they get the same type of structured

results.The results of a query are often iterated through using a cursor.However, instead of

crafting queries,we use URIs.

 

You can think of a URI as an "address" to the location where content exists. URI addresses

are hierarchical. Most content providers, such as the Contacts and the

MediaStore, have URI addresses predefined. For example, to access images the External

Media Device (also known as the SD card),we use the following URI defined in the

MediaStore.Images.Media class:

Uri mMedia = Media.EXTERNAL_CONTENT_URI;

 

 

Retrieving Content Provider Data with managedQuery()

We can query the Media Store content provider using the URI much like we would

query a database.We now use the managedQuery() method to return a managed Cursor

containing all image media available on the SD card.

String[] projection = new String[] { Media._ID, Media.TITLE };

Uri mMedia = Media.EXTERNAL_CONTENT_URI;

Cursor mCursorImages = managedQuery(mMedia, projection, null, null,

Media.DATE_TAKEN + " ASC"); // Order-by clause.

We have retrieved the records for each piece of media available on the SD card.

Now we have this Cursor, but we still have some legwork to get our Gallery widget

to display the individual images.

 

Data-Binding to the Gallery Control

We need to extend the BaseAdapter class for a new type of data adapter called

ImageUriAdapter to map the URI data we retrieved to the Gallery widget. Our custom

ImageUriAdapter maps the Cursor results to an array of GalleryRecord objects, which

correspond to the child items within the Gallery widget.Although the code for the

ImageUriAdapter is too long to show here,we go over some of the methods you must

implement for the adapter to work properly.

 

The ImageUriAdapter() constructor is responsible for mapping the Cursor to an

array of GalleryRecord objects, which encapsulate the base URI and the individual

image's id.The image id is tacked on to the end of the URI, resulting in a fully

qualified URI for the individual image.

 

The getItem() and getItemId() methods return the unique identifier for the specific

image.This is the value we require when the user clicks on a specific image

within the Gallery.We save this information in our database so that we know

which image corresponds to which pet.

 

The getView() method returns the custom View widget that corresponds to each

child View within the Gallery. In this case,we return an ImageView with the corresponding

image.We set each view's Tag property to the associated GalleryRecord

object, which includes all our Cursor information we mapped for that record.This

is a nifty trick for storing extra information with widgets for later use.

After all this magic has been implemented,we can set our newly defined custom adapter

to the adapter used by the Gallery with our new Cursor.

I             mageUriAdapter iAdapter = new ImageUriAdapter(this,

mCursorImages, mMedia);

final Gallery pictureGal = (Gallery) findViewById(R.id.GalleryOfPics);

pictureGal.setAdapter(iAdapter);

 

Retrieving Gallery Images and Saving Them in the Database

Notice that we added two new columns to our SQLite database: the base URI for the

image and the individual image id, which is the unique identifier tacked to the end of the

URI.We do not save the image itself in the database, only the URI information to retrieve

it.

When the user presses the Save button on the Pet Entry screen,we examine the

Gallery item selected and extract the information we require from the Tag property of

the selected View, like this:

final Gallery gall = (Gallery) findViewById(R.id.GalleryOfPics);

ImageView selectedImageView = (ImageView) gall.getSelectedView();

GalleryRecord galleryItem;

if (selectedImageView != null) {

galleryItem = (GalleryRecord)selectedImageView.getTag();

long imageId = galleryItem.getImageId();

String strImageUriPathString = galleryItem.getImageUriPath();

}

We can then save our Pet Record as we have before.

 

Displaying Images Retrieved from the SD Card Using URIs

Now that our Pet Entry form is saved properly,we must turn our attention to the Pet

Listing screen. Our ListView is getting more complicated; each item needs to contain an

ImageView and two TextView widgets for the pet name and species.We begin by defining

a custom layout template for each ListView item called pet_item.xml.This should be familiar;

it contains an ImageView and two TextView objects.

We want to make sure this implementation is scalable, in case we want to add new features

to individual ListView items in the future. So instead of taking shortcuts and using

standard adapters and built-in Android layout templates,we implement another custom

adapter called PetListAdapter.

The PetListAdapter is similar to the ImageUriAdapter we previously implemented

for the Gallery widget.This time, instead of Gallery child items,we work with the

ListView child records, which correspond to each pet.Again, the constructor maps the

Cursor data to an array of PetRecord objects.

The getView() method of the PetListAdapter is where the magic occurs. Here we

use a LayoutInflater to inflate our custom layout file called pet_item.xml for each

ListView item.Again we use the Tag property of the view to store any information about

the record that we might use later. It is here that we use the URI information we stored

in our database to rebuild the fully qualified image URI using the Uri.parse() and

ContentUris.withAppendedId() utility methods and assign this URI to the ImageView

widget using the setImageURI() method.

String asColumnsToReturn[] = {

Pets.PETS_TABLE_NAME + "." + Pets.PET_NAME,

Pets.PETS_TABLE_NAME + "." + Pets.PET_IMAGE_URI,

Pets.PETS_TABLE_NAME + "." + Pets._ID,

Pets.PETS_TABLE_NAME + "." + Pets.PET_IMAGE_ID,

PetType.PETTYPE_TABLE_NAME + "." + PetType.PET_TYPE_NAME };

mCursor = queryBuilder.query(mDB, asColumnsToReturn, null, null,

null, null, Pets.DEFAULT_SORT_ORDER);

startManagingCursor(mCursor);

SetListAdapter adapter = new PetListAdapter(this, mCursor);

ListView av = (ListView) findViewById(R.id.petList);

av.setAdapter(adapter);

That's about it. Note that you can also create the ListView item layout programmatically.

 

Now you've seen how to leverage a content provider to make your application more

robust, but this example has scratched only the surface of how powerful content

providers can be.

 

0 件のコメント:

コメントを投稿