Adapter / ArrayAdapter

Adapters – Part 3

In the previous article we got an ArrayAdapter and a slightly more complex SimpleAdapter working, but suggested that we could also achieve the same result as the SimpleAdapter using an ArrayAdapter. In this article we’ll look at how to do this, but also explore some performance issues which we need to be aware of when working with Adapters.

In principle, replacing the SimpleAdapter with an ArrayAdapter is relatively simple. We create a class to hold the data for each item:

We can then use an ArrayAdapter instead of the ArrayAdapter that we used previously. The only problem here is that ArrayAdapter has no implicit knowledge of our Item class, so we need to perform the actual data binding ourselves. We do this by creating our own ArrayAdapter implementation and overriding the getView() method:

Hopefully this should be fairly understandable, and it does precisely what we require:

ArrayAdapterObject

However, there is a problem with this, as you may be able to guess from the comment in the getView() implementation. To understand the problem, we have to consider how ListView works, particularly when we are scrolling through a list. Each time an item in the ListView comes in to view when scrolling, getView() will be called. Our getView() implementation is performing two quite expensive operations: layout inflation, and finding views within the layout.

Layout inflation is expensive because it requires the parsing of XML and the creation of a number of object instances representing the controls within the XML.

Finding views is expensive because it requires traversal of the view hierarchy in order to find the control that we’re interested in.

The net result of having these expensive operations within our getView() method is that the scrolling of our ListView will not be smooth. This will be compounded because the items going out of view will need to be garbage collected by the VM in order to free up the memory that will be necessary to create new objects during view inflation, and garbage collection is also an expensive operation.

Fortunately the Adapter framework gives us a mechanism for recycling our item layouts. When items go out of view, their layouts will be recycled and they will be passed in to our getView() method in the convertView argument. So we can perform a null check on this, and only inflate the view if we have to:

This will optimise performance quite considerably but we’re still performing these expensive findViewById() calls each time getView() is called. Now that we are re-using our layouts, the actual TextView objects that we’re binding to are also being reused so we can cache them. We can do this by using a View Holder pattern where we create a new object containing references to our controls and attach this to the parent layout:

Now we only perform the layout inflation and findViewById() calls when we absolutely have to, thus keeping the code in getView() much more efficient. You should always avoid expensive calls such as filesystem and network operations in the getView() method.

In the next article we’ll have a look at how we can bind images to an ImageView within our item layout without making expensive calls in getView().

The source code for this article is available here.

© 2013 – 2014, Mark Allison. All rights reserved.

CC BY-NC-SA 4.0 Adapters – Part 3 by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Permissions beyond the scope of this license may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

Your email address will not be published. Required fields are marked *