This is the second in a series of posts about Droid-Fu, a shiny new shared library for Android application developers. In this post I will introduce two very handy components: WebImageView and WebGalleryAdapter.
WebImageView: Buy one, get two!
Many mobile apps make heavy use of web based content, especially photos, avatars, and other images. The problem with that is: you have to download the images before being able to display them, which has basically three important implications:
- the download has to be asynchronous, otherwise your UI will lock up
- while the download is processing, you have to keep the user happy by displaying some kind of progress indicator
- downloading stuff means you’re sucking away on your user’s quota, hence, you typically want to cache downloaded images.
That sounds like an awful lot of stuff to care about for achieving a rather underwhelming effect: displaying an image. Fortunately, there is a dead simple way to get all this in one handy small package: Droid-Fu’s WebImageView.
Here is an example of what it can look like. The first screenshot shows WebImageView in its loading state, using a grey solid background (of course you can change that) and the stock progress spinner (you can change that, too). The second screenshot shows the fully loaded image.
If you haven’t already downloaded and linked the Droid-Fu JAR to your project, do that now. Then, in your layout, add this:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:droidfu="http://github.com/droidfu/schema" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:background="#FFF" > <com.github.droidfu.widgets.WebImageView android:id="@+id/webimage" android:layout_width="75dip" android:layout_height="75dip" android:background="#CCC" droidfu:autoLoad="true" droidfu:imageUrl="http://www.android.com/images/opensourceprojec.gif" droidfu:progressDrawable="..." /> </LinearLayout>
All arguments are optional, this allows you to define your view first, and then trigger loading the image programatically using WebImageView.loadImage(). Easy, huh?
WebImageView is backed by ImageLoader, Droid-Fu’s generic way of fetching images from the web. ImageLoader itself is backed by a two-level cache. When you load an image using WebImageView (or ImageLoader), what happens is that the 1st-level (in-memory) cache is queried for the required bitmap. If it’s a hit, it’s served immediately. If it’s a miss, the request drops through to the 2nd-level cache, which is the disk cache. Droid-Fu uses your app’s cache directory, which is managed by Android, so you don’t have to worry about maintenance stuff. If this request also misses, then WebImageView will finally go ahead and download the image from the web.
Be careful not to set the cache size too big. Cache size is currently defined in terms of “number of images” instead of “number of bytes”, so if you know you’re gonna download large high-res images, set this to a small value, otherwise you’ll see OutOfMemory errors. Forget that last paragraph. Meanwhile, I have changed the in-memory cache implementation. It’s now a weak-reference backed hash created by the Google Collections MapMaker, the capacity of which will automatically scale with the available memory. Simply put, if there’s not enough memory left, any cache entry will be garbage collected, unless there is still a strong reference to it (e.g. because it’s currently displayed to the user).
So how else can you make use of this? Well, I don’t know, but I know that I already made use of this when implementing WebGalleryAdapter. This class serves as an adapter for Android’s Gallery widget, and it’s completely plug-and-play: Create your gallery, call setAdapter() with a WebGalleryAdapter instance, and pass it a bunch of image URLs. Whenever the user then scrolls/flings through the images in your gallery, the images will be fetched automatically from the web, with all the features such as caching and progress indication as described before.