What are bitmaps?
Images come in two flavours, Vector Graphics and Bitmaps. Bitmap images are stored as a map of bits, sometimes also referred to as a map of pixels.
You may want to read Designing for multiple screens. Alternative image resources, for more on using images in your apps.
Images also come in different sizes. Bigger images have more pixels so they take up more space. They also take longer to download and to display.
It’s all about Memory
Android devices have a limited amount of memory which has to be shared amongst the operating system and the apps running on the device.
Bigger images use more memory and can make your app unresponsive.
There are techniques that you can use when working with images to make them load faster:
- Scale down - Put a smaller version of the original in memory
- Do all the processing of the image off the main thread
- Recycle image views and take care of processing images at the same time
- Save your images in a cache for faster reloading. Use both a memory and a disc cache
There are two ways of doing this:
- Do it all yourself
- Use a library that takes care of it for you
Doing it yourself
Check out the documentation. There’s quite a bit of coding involved.
Loading large Bitmaps efficiently
Processing Bitmaps off the UI thread
Let the Picasso Library do it for you
There are a few image processing libraries to choose from. At the time of writing, Picasso seems to be one of the best so we’re using it in our tutorial app.
If you’ve checked out the code in the links above, you’d have seen that there is quite a lot of coding involved. Enter Picasso!
In Picasso it’s all taken care of in ONE SINGLE LINE OF CODE. Seriously!
Picasso
Picasso is a powerful image downloading and caching library package which you include in your app build. It simplifies working with images, reducing the code that you need to use to one line of code.
Picasso is fast and easy to use.
Picasso takes care of all your image processing for you. It can also download images.
So what can Picasso do for you?
- You can download single images or many if used inside an adapter. It automatically detects adapter reuse and cancels the download. It’s done on a separate thread too
- You can load your images from Content providers, assets, files and resources
- You can transform your images by resizing and cropping them with minimal memory use
- You can include download and error placeholders
- Your images are automatically cached in memory and on disc. Different transformations of the same image can be stored for future use
- Any unused image views are automatically recycled
- Your images are displayed in your image views
- You can also display a colour marker while developing. Useful if you want to see where your image is being loaded from (memory or disc)
Oh, and did I mention it’s free and Open Sourced?
Check out the Picasso website
The tutorial app
Our tutorial app displays a list of items. Each item includes an image and a line of text. The user can select an item which displays a larger image with some extra text.
The images are loaded from a drawables folder.
The list items display an image and some text
Note the following:
- The original image has been scaled down in size so that it can be included in the list
- While developing, you can display a small colour triangle in the top-left corner of the image. This indicates where the image is being loaded from:
- Green – loaded from memory
- Yellow – loaded from disc
Selecting the Golden Silence item displays a larger image and some text. This image has been loaded from the disc
Selecting the item again, loads the image from the memory cache
The Main activity
The main activity displays a list of items. The items include both an image and some text. Selecting an item displays a larger image and some text detail in a fragment.
Each item is created using a person class.
The Person class
The fields in the class are:
- Name – String
- Image resource id – int
- A phrase – String
- Phone number - int
Populating the list
To populate our list, we first create a Person list object, people:
Our list consists of an array list of Person objects
We use our populatePersonList() method to populate the list:
We add our Person objects to the list in the populatePersonList() method
Note the following:
- Add – adds the Person object to the end of the people list
Our List layout
Our main activity’s layout includes a ListView view which takes care of displaying the scrolling list
Populating the list view
We populate the list view in the populateListView() method:
Our custom ArrayAdapter populates our list view using the items in our people list
Note the following:
- adapter - an instance of our custom array adapter
- list – our list view which displays the list in the main activity. It’s in the activity_main.xml file
- setAdapter – we set the adapter to be used to supply the data to the list view
Creating our custom adapter
We create our own adapter to supply our image and text to the list.
Here’s the code:
We create our custom ArrayAdapter MyListAdapter and return a view for each item
Note the following:
- we use the item_view.xml layout to display each item row in the list. This is where you can customise the look of each row
- getView – this gets a view to display each item in the list. It has three parameters:
- position – the position of the item in the adapter. It’s this item’s view that we want to display
- convertView – an old view that we may be able to re-use
- parent – this is the parent list view that will display this item view
- itemView – this is the item view that we will return and display in the list. We try and re-use the convertView if possible. Otherwise we create a new item view by inflating the item_view.xml layout file
- currentPerson – we get an instance of the list item identified by its position in the list
- ImageView – we get an instance of the image view. We’ll use it to display the thumbnail image in the list
- nameText – we get an instance of the text view. This will display the name string
- return itemView – we return the item view. This will display this item in the main list
- Picasso – this takes care of getting the image, resizing it, storing it in both memory and disc cache and making it available for display. It also takes care of recycling the image views no longer used
- setDebugging – used in development. If true, a colour triangle will display in the top-left corner of the image. Yellow indicates that the image was loaded from disc while green indicates that it was loaded from memory
We’re using the Picasso library which you must include in your build. Have a look at Loading the Picasso Library into your app build to see how to do that.
Selecting an item
When a user selects an item, we display a full image and some text in a fragment.
You may want to look at Dynamic layouts using fragments for more on fragments.
Here’s the code that takes care of the item selection:
Selecting an item gets the details of that item. These are passed on to a new activity which creates and displays a fragment containing the details
Note the following:
- We attach the listener to our list view
- The onItemClick() method is executed when an item is selected
- clickedPerson – we use the position parameter to identify which list item was selected
- get
- we use the get () method to get the relevant values for the selected item - intent – we create a new Intent which we’ll use to start the DetailsFragmentActivity activity
- putExtra – we put the values into the intent. We’ll use these values when we create the fragment
- startActivity – we start the DetailsFragmentActivity activity
Check out Passing data between activities for more on using intents to pass data to activities.
The Fragment
We use a fragment to display the full image and extra text detail for the selected item. The fragment is created by and displayed in the details fragment activity.
The details fragment activity
The details fragment activity creates and displays a fragment containing the details of the selected item.
We get the selected item’s data out of the intent that started the activity. Then we put the data into the new fragment object.
Here’s the main bit of code:
We create a new fragment, passing it the selected item’s details
Note the following:
- args – a Bundle object that we put our selected item’s details into
- put
- we use the put () method to put our data into the bundle - setArguments – we put the bundle into the fragment object
- getSupportFragmentManager – we’re using the Support Library so we get an instance of the fragment manager using getSupportFragmentManager
- replace – we replace whatever’s showing in the container with our new fragment
The fragment’s layout
The DetailsFragmentActivity activity’s layout contains the fragment’s container FrameLayout view:
Our fragment’s container view
The Details fragment
The details fragment displays the selected item’s details in a new fragment.
Here’s the one line of code needed to get the image, resize, crop and then display it in the image view. It also takes care of caching the image in both memory and disc and recycling the unused image views:
One line does it all: loads, resizes, transforms, caches and displays the image
Note the following:
- with – the context of the Picasso instance
- load – we’re using a drawable resource. You could also pass an URl, File or file path
- resize – resamples the image to produce the required size
- centerCrop – resizing the image to fit the required size and then crops the excess
- into – asynchronously loads the image into the image view. It also recycles the image views no longer used
You can change the configuration of the default Picasso instance if you want. Check out the Picasso documentation
You may want to have a look at our GridView tutorial where we used Picasso to handle the images: GridView tutorial using the Picasso Library
I hope that you have found this tutorial helpful.
If you need more info on ArrayAdapters and lists, have a look at our Android ListView tutorial.
You can download the project files here