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 件のコメント:
コメントを投稿