Brain Flush

November 23, 2009

Droid-Fu, Part 2: WebImageView and WebGalleryAdapter

Filed under: Software Development & Programming — Tags: , — Matthias @ 11:19 pm

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:

  1. the download has to be asynchronous, otherwise your UI will lock up
  2. while the download is processing, you have to keep the user happy by displaying some kind of progress indicator
  3. 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.

 

Using WebImageView

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?

Caching

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).

WebGalleryAdapter

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.

Advertisements

November 16, 2009

Introducing Droid-Fu for Android: BetterActivity, BetterService and BetterAsyncTask

Filed under: Software Development & Programming — Tags: , — Matthias @ 9:54 pm

This is the first in a series of posts about Droid-Fu, a shiny new shared library for Android application developers. In this post I will introduce some of the ideas behind Droid-Fu, and start by showing off some of its core features.

What is Droid-Fu?

  • Droid-Fu is a general purpose Android application library, deployed as a JAR
  • Droid-Fu’s primary purpose is to make your Android developer life easier
  • Droid-Fu is open source! (fork it, hack it, share it, all on GitHub)
  • ain’t that enough?

Droid-Fu contains utility classes as well as some self-contained, ready to use Android components, all of which I consider useful for typical Android applications. Some of the areas for which Droid-Fu offers support classes include:

  • application life-cycle
  • background tasks
  • HTTP messaging
  • (remote) image handling
  • custom adapters

… and more. The library is still young, so expect to see a lot more stuff forthcoming!

Who uses it?

Droid-Fu contains mostly code which I pulled from Qype Radar, our geo-sensitive mobile application which let’s you find, review, and share all those cool places near you. In other words, Droid-Fu is used in a production quality app, and even though it’s a WIP, we find it to be quite solid. Of course you’re invited to make it even better. Did I mention it’s open source?

The Foundations

One of the strongest (in my opinion) benefits of using Droid-Fu are its application life-cycle helpers. If you are developing an application which performs background work, such as fetching data from the web, you will almost definitely want to Droid-Fu-idize your app. Here’s why.

That Dratted AsyncTask

I’ve written about this two times now. I think with this third approach, which made it into this library, I finally found a decent solution. But, let’s review the biggest problem with Android’s AsyncTask, first. What is AsyncTask? It’s Android’s helper class you’re supposed to use for performing expensive (that means, blocking) operations. If you’re writing an app that talks to a web service, you’ve very likely already used it. (You’re not doing all that work on the UI thread, do you? If you do, chances are your activity will only live for a couple seconds, because Android kills non-responsive activities. ANR, anyone?)

So the basic idea is: launch an AsyncTask making your service call, show a nifty progress dialog while the task thread is running, and have the task’s result be posted back to your activity once it completes. Cool, but what if the user decides to rotate the screen while your task is running? Or a phone call comes in, interrupting your app, and Android decides to kill it? Both these actions will effectively terminateyour activity, and recreate it when resuming (yes, a screen rotation kills your activity, very clever, isn’t it?). Unfortunately, any AsyncTask that was still running now holds a stale reference to your activity, because the restarted activity will be an entirely different object in memory (and it will go through onCreate(), as if the activity had started for the first time). I’m not entirely sure whether AsyncTask will actually post back the data to the old activity object (if it was a weak reference, it may already have been garbage collected), but in any case, your “new” activity will never see it, because it’s a different instance.

Now, one could argue: well, just do all the work again, like, re-send the request or whatever job was running. Yes, you could do that. But that’s wasteful and, really, makes you feel stupid, no? Plus, if the user triggers a web service request, then flips the screen, decides that this wasn’t helpful, and flips it back, then your request is being sent 3 times in parallel. Is that what you want? Probably not.

BetterAsyncTask to the Rescue

Thanks to Droid-Fu, there’s a solution to this: BetterAsyncTask! (I’m a lazy person, and I couldn’t come up with a better name). It behaves exactly like AsyncTask (in fact, it is an AsyncTask), but it does some extra work for you: first and foremost, it keeps track of the active instance of the context that launched it, and if that instance should change, it will post the data back to the new instance. In other words, you can dispatch your task, flip the screen back and forth mentally, and BetterAsyncTask will still post the task’s result back to whatever activity instance is alive at the time it finishes. In other words, the task is only ever run once, regardless whether the context in which it was launched died while it was running or not.

There’s a catch though. Since there is no way for BetterAsyncTask to figure out which one is the current instance of its activity, it relies on a helper: DroidFuApplication. This class derives from Application, and if you want to use BetterAsyncTask, your application has to derive from that class, otherwise it won’t work. That’s because DroidFuApplication keeps a hash of WeakReferences mapping contexts (activites and services) to their active instances, and when a BetterAsyncTask finishes, it will ask your application for the active instance.

This is all you have to do to launch a task showing the standard Android indeterminate progress dialog:

public class MyActivity extends BetterDefaultActivity {

 protected void onResume() {
   super.onResume();

   if (isLaunching()) { // this is explained further down this article
     MyBetterAsyncTask task = new MyBetterAsyncTask(this);
     task.execute(someData);
   }
 }

}

It doesn’t end here though. BetterAsyncTask does other cool stuff, such as automatically opening and closing progress dialogs for you while it’s running, or triggering that little progress spinner in the activity title bar when your activity has enabled that feature. It also allows your task to throw exceptions in its worker method, which are then posted to an error handler you define. Some of that stuff, like spawning dialogs, only works if your activities inherit from BetterActivity, which I will get to now.

BetterActivity and BetterService: Pimp my context!

Droid-Fu provides base classes for your activities and services which provide some simple but very useful helper methods. Currently, there are only BetterDefaultActivity, BetterListActivity and BetterService, but I intend to implement the Better* stuff for all stock Android activity base classes (like MapActivity and all the others).

Here is what you get:

Life-cycle helpers

these methods let you conditionally perform work depending on a context’s life-cycle state.

  • isLaunching() is true if and only if the context just went through onCreate() for the first time (but was not restored, i.e. onRestoreInstanceState() was not called)
  • isRestoring() is true if your context is recovering after being killed by Android
  • isResuming() is true if your context is “soft-resuming” as I call it, i.e. there was no call to onCreate() before going through onResume()
  • isApplicationBroughtToBackground(): sometimes it’s necessary to distinguish between your activity being paused by another activity of your own application, or by an entirely different application. This method yields true if another application’s activity is hiding yours.

Dialog helpers

BetterActivity offers the following helper methods to easily let you spawn dialogs:

  • showInfoDialog(): shows an alert dialog with an info icon
  • showAlertDialog(): shows an alert dialog with a warning icon
  • showErrorDialog(): same as alert dialog, but takes an exception as an argument
  • showListDialog(): shows a dialog with a list of Ts (T is some generic type). When clicking an entry, it will call back to a handler with the T that was selected.

all dialogs are customizable (e.g. message or icon).

There is more to come!

There’s a lot more in Droid-Fu at the moment (will cover that in upcoming posts), and there will be even more in the future, since I’m continually working on this library.

Cool, where can I get it?

The Droid-Fu source code is currently hosted on GitHub, which is the place where the cool kidz hang out these days. It’s a maven project, but the JARs aren’t yet hosted anywhere. Anyway, just check it out using git clone:

git clone git://github.com/kaeppler/droid-fu.git

and run:

mvn install -DcopyTo=path/to/your/apps/lib/dir

(you need to install git and maven2 for all that magic to work).

Happy coding!

Create a free website or blog at WordPress.com.