Android SDK: Displaying Images with an Enhanced Gallery

Using Android Intents and the Gallery View, you can allow the user to select images from their device. In this tutorial we will combine user image selection with the Gallery View, which we will enhance a little to create an interactive display featuring the user's chosen images. If you have completed at least one Android application, you should be able to carry out the steps in the tutorial.

The app we will build in this tutorial is going to display a scrolling list of thumbnail images, using the Android Gallery View. The user will be able to import images to display by long-pressing the items in the Gallery, on which they will be taken to the default Android gallery application or their chosen file manager. When a selected image is returned to the app, we will resample it before display, so that we don't use unnecessary memory resources. On pressing a thumbnail, the app will display the selected image at a larger size.

Step 1: Create an Android Project

Start a new Android project in Eclipse. In your app's main Activity class, add the following import statements at the top, before the opening class declaration line:

Your class declaration should begin something like this, but with your own Activity name:

Inside the class declaration, before the "onCreate" method, which Eclipse should have automatically included, add these instance variable declarations:

The first variable, which is a constant, is for identifying the image chooser Intent when the user's chosen image is returned to the app. When the user long-presses a thumbnail item and is taken out of the app to choose an image, we will use the "currentPic" variable to keep track of which thumbnail they are selecting an image for. The other two variables are for user interface items we need to reference in the class.

In your manifest file, the only addition you should need is the following, added to your app's main Activity element:

This will allow the app to retain imported images on orientation changes. Now let's setup the text Strings we want to use within the user interface. Open your "res/values/strings.xml" file. Eclipse should have added your application name already, which you can alter if you wish. Include the following additional String elements:

These are all for use within the user interface. Now go back to your app Activity class.

Step 2: Design the App

Before we implement the app functionality in Java, let's complete the design elements. Open your "res/layout/main.xml" file. We will be using a Linear Layout, so include the following outline in your main XML:

We will be adding more elements inside the Linear Layout. Start with an informative Text View as the first item in the Linear Layout:

Notice that we refer to a String we defined in the strings XML file. Next add the Gallery element as follows:

We use an ID attribute so that we can refer to the Gallery in the Java code. Next add another informative Text View:

Again, we use a string resource already defined. Finally, the last item in our Linear Layout is going to be an Image View for displaying one Gallery image at larger size:

We need to refer to this View in Java, so we use an ID attribute. We also use a string resource as the content description. Now we need to define some style attributes for the Gallery. Create a new file in your "res/values" directory, naming it "attrs.xml". Enter the following code:

We are going to use some of the Android platform style resources to style our Gallery items, and will refer to these in the Java code.

Now go back to your Activity class. Inside the "onCreate" method, your existing code should appear as follows:

After these lines, add the following, retrieving references to two of the user interface items:

Now we are ready to build the Gallery and handle user interaction.

Step 3: Create a Base Adapter

To build the Gallery View, we're going to create a class which extends the Base Adapter class. In your Activity class, after the "onCreate" method, create a new inner class outline as follows:

Inside this we will provide a few methods that are required by the Base Adapter and later will add some custom methods for this app. First, inside the new class, add some instance variables:

The first variable represents the Android Gallery item background we referred to in our "attrs.xml" file. The Context is for referring to the user interface when adding elements. The Bitmap array will store the bitmaps we are going to display as part of the Gallery View. To start with, we will use a placeholder image, for Gallery items the user has not selected images for yet.

Let's go ahead and create the constructor method for our new PicAdapter class, after the instance variables:

We will add more code to the constructor method next. Here we first instantiate the Context and Bitmap array variables - we are going to display a Gallery with 10 items in it but you can alter this if you like. For demonstration, we are using the launcher icon provided as standard when you create an Android project in Eclipse as our placeholder image, but you can of course create your own. If you do want to use your own image, save it to your drawable folders and alter the "decodeResource" line in the above code to reflect its name.

Now we can assign the placeholder image to each position in the array, so that all of the Gallery thumbnails will initially display it - still inside the constructor method:

To complete the constructor method, we now set the Gallery item background image:

Here we refer to the content of our "attrs.xml" file.

Now we need to provide a few standard methods for any class extending the Base Adapter class. First include the "getCount" method, after the constructor method:

This method returns the number of items in the Gallery View. After this method, add the standard "getItem" method:

Next add the "getItemId" method:

You don't need to worry too much about the content of these methods as they are standard. Now we add a slightly more complex method required by the class:

In the "getView" method, we define what we want to appear within each Gallery item. Our Bitmap array is going to contain the images we want to display at each position, with an Bitmap's array index corresponding to its position within the Gallery. As well as creating the View, here we set the Bitmap to appear within it, together with a few display properties. We also set the item background we referred to earlier. You can alter the thumbnail size if you like. Each thumbnail image will appear centred if it is smaller than the item View - you can opt, for example, to stretch the image to fit the thumnbail if you prefer, by altering the "ScaleType".

Now scroll up to the top of your app's main Activity class declaration. Add a new instance variable representing an object instance of the new class you just created:

Now, in the "onCreate" method, after the code you already added, instantiate your Base Adapter variable and set it as the adapter for the Gallery:

When the app initially launches, it will look something like this:

Pic Select Launch

Now we are ready to handle user interaction.

Step 4: Allow the User to Choose Images

To select images to display in the Gallery, the user is going to long-press individual thumbnail items. In your "onCreate" method, after the existing code, add the following long-press listener for each item in the Gallery View:

Here we create a new "OnItemLongClickListener" with an "onItemLongClick" method inside it. Inside this method, add the following code:

Take a moment to look over this code. First, we record the currently selected item so that we know which Gallery item a new image is being chosen for. Then the code tells the app to take users to their chosen image selection app, which may be the Android image gallery or a file manager application. By specifying "ACTION_GET_CONTENT", we are instructing the app to return whatever the user selects. Since we start the chooser Intent using "startActivityForResult", we will be able to handle the returned image in the Activity "onActivityResult" method.

What happens when the image chooser Intent starts will depend on which applications the user has installed. On my device, I can choose between two apps for image selection:

Image Chooser App Choice

Whichever image file I select in either of these applications will be returned to our app.

Step 5: Handle Returned Images

When the user selects an image from their gallery or file manager app, the data will be returned to the "onActivityResult" method. Add the method to your Activity class using the following outline:

Here we check that we have received valid data and that the data has returned from the image selection Intent. We call the superclass method at the end of the method body. Inside the second "if" statement, we will add all of the code we need to import the user's chosen image, starting with the image URI:

We need to do a little more work to import the image. Start by declaring some helper variables:

Let's now attempt to retrieve the image path:

Here we retrieve the image media data, then query it using a cursor, passing the URI for the image chosen by the user. The "if" and "else" statements accommodate the user choosing their image using either the Android gallery app or another file manager. The end result of this code is that we have the path to the chosen image.

Step 6: Display Sampled Images to Minimize on Memory Usage

Rather than simply reading in the user's chosen image, we need to minimize on the amount of memory our app uses. In many cases, images on the device will be much larger than what we can display within the app. For this reason, we want to resample each image before reading it into the app. Still inside the second "if" statement in "onActivityResult", add the following:

Inside this statement we will resample and import the image. Begin by specifying the target width and height for your images, which should be the largest size you want each image to appear:

Now we need a Bitmap Options object to handle decoding the image:

First we want to find out about the size of the image:

We tell the Bitmap Options to decode the dimensions of the image, not the Bitmap itself. We are going to use this information to work out a good sample size to import the image at, start by initializing a variable to store it:

Now calculate the sample size, if the target size is smaller than the image's default size:

Now we can set the Bitmap sample size:

Now we need to alter the Bitmap Options settings in order to decode the file content itself, rather than just its dimensions:

Finally we can decode the Bitmap using our chosen options:

The "pic" variable now holds the Bitmap image we want to use in the app.

Step 7: Add Chosen Images to the Gallery

Now that we have the user's selected image imported, we can add it to the Gallery array. We need to add a custom method to our Base Adapter class to do this. Inside your "PicAdapter" inner class declaration, add the following method after the "getView" method:

Now go back to your "onActivityResult" method, after the line in which you decoded the image file, storing it in the "pic" variable, add the following:

First we call the new method to add a new image to the Gallery array, then we set the Adapter again so that the new image will instantly appear within the Gallery View.

Step 8: Display One Image at Larger Size

Finally, we want to display one image at larger size. An image will appear in the larger Image View when it is initially imported into the app and when the user selects it from the Gallery thumbnails. First, let's handle showing an image at larger size when the user initially imports it. In your "onActivityResult" method, after the line in which you called "setAdapter", add the following:

We have an instance variable representing the larger Image View, so can simply set it together with scaling options. Now let's handle displaying the larger image when the user clicks a thumbnail. In your "PicAdapter" class, add another custom method after the "addPic" method:

This method simply returns the image at the specified position. Now go to your Activity "onCreate" method. After the long-press listener you added, include the following, implementing a click listener for each item in the Gallery View:

The "onItemClick" method will fire any time the user clicks an item in the Gallery. We call the new "getPic" method we added to the "PicAdapter" class to return the Bitmap at the clicked position, setting this as the Image View Bitmap to display it at larger size.

Conclusion

That's our image gallery app complete. Test it on an actual device, importing images by long-pressing thumbnails and pressing each thumbnail in turn to display it at larger size. When the user has selected a few images, the app will appear something like this:

Gallery with Selected Images

You can of course enhance the application to suit your own needs, for example to provide additional image interaction. The source code is provided for reference, so you cna make sure you have all the elements combined correctly.

Tags:

Comments

Related Articles