Tuesday, December 02, 2008

Using a Horizontal Progress Bar in Android

I was working on my Android downloader application yesterday, when I ran into a bit of a snag. I wanted to display a list of downloads (similar to the Firefox downloads window). Each item in the list should show the file name and a horizontal progress bar. I started to implement this, and several hours later stumbled upon the arcane solution. I wanted to share this, both to help anybody who may be trying to do something similar, and also to illustrate how the lack of good documentation is hurting aspiring Android developers.

I thought that I could put a ProgressBar instance in my xml, set it to be indeterminate, give it a max and a value, and be done. However, it wasn't nearly that easy. After a few hours of hunting on Google and the Android Groups, I stumbled upon the solution in an online preview of The Busy Coder's Guide to Android Development. In short, I had to set the following on my ProgressBar's XML:

style="?android:attr/progressBarStyleHorizontal"
WTF?

Let's try to break this down. The ? on the front indicates that this is a reference to something in the current theme. What is a theme? Well, Android's UI infrastructure is similar to Swing or HTML in that it tries to accommodate components whose size is not known until runtime. Android's components are also themeable (similar to the Swing Synth LAF). A theme is a collection of related component styles. You can control the theme used by your application in the AndroidManifest.xml file. So, I think we can safely conclude that attr/progressBarStyleHorizontal is something whose actual value is defined in a particular theme.

If you take a peek in the android source code, inside frameworks/base/core/res/res/values/attrs.xml, you will find the following definition:

<resources>
<declare-styleable name="Theme">
<!-- snip -->
<attr name="progressBarStyleHorizontal" format="reference" />
OK, not very useful. However, in frameworks/base/core/res/res/values/themes.xml, we find:
<resources>
<style name="Theme">
<item name="progressBarStyleHorizontal">@android:style/Widget.ProgressBar.Horizontal</item>
Nowe we're getting somewhere. Finally, inside frameworks/base/core/res/res/values/styles.xml, we see:
<resources>
<style name="Widget.ProgressBar.Horizontal">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
</style>

What's going on here? Well, it looks like themes.xml defines a theme as a collection of styles. Along with that, styles.xml specifies a set of attributes that should be applied to a particular XML element. By saying

<ProgressBar style="?android:attr/progressBarStyleHorizontal">
we are really saying
<ProgressBar style="@android:style/Widget.ProgressBar.Horizontal">
which is like saying
<ProgressBar 
android:indeterminateOnly="false"
android:progressDrawable="@android:drawable/progress_horizontal"
android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal"
android:minHeight="20dip"
android:maxHeight="20dip">
Spiffy.

For bonus points, we can look in frameworks/base/core/res/res/drawable/progress_horizontal.xml. This file apparently contains the declarative expression of the horizontal scrollbar graphic. I don't know how extensive this syntax is, but a quick peek at progress_indeterminate_horizontal.xml indicates that it is possible to specify animations in this XML file format.

All this seems really powerful, only somewhat useful, and totally confusing. All I wanted was to create a horizontal progress bar. I can't tell why the Android widget collection includes only one ProgressBar class that is meant to be used for horizontal, indeterminate horizontal, indeterminate circular, and every other kind of possible progress indicator. Perhaps there would be duplication of code if those were separated into different classes. Whatever. I actually don't mind that they stuffed all those progress indicators into a single class. There are some questionable decisions (like having both indeterminate and indeterminateOnly), but I can deal with it. On the other hand, the incantations that you have to use to get the Progress Bar to behave are truly arcane. I think I have proven in this blog post that there is some method to the madness and, as is often the case, easy access to the source code is a must. What bothers me most is that there was absolutely no documentation on the subject. Google seems silent on this topic, and even The Busy Coder's Guide mentions that the style attribute won't be covered until a later edition of the book (though it is possible that the Google Books sample chapter is out of date at this point).

I still maintain that Android is one of the most unique application systems that I've seen. However, as I've tried to develop for it, I have encountered a general lack of polish. Many things that you want to do as a developer are confusing and poorly documented. Familiarity with existing technologies (such as Swing or Applet programming) is pretty much useless here. On the other hand, the core concepts (such as the use of Intents to start applications and communicate between processes, the HEAVY use of message passing, and the declarative nature of the AndroidManifest.xml file) seem to be an excellent base upon which to build not just an open operating system, but a truly open user experience. A power user can really replace virtually any aspect of the system. Perhaps developers will create third party libraries that make Android a little easier within which to develop, or maybe Google itself will provide simpler interfaces for developers. Or perhaps Android will die out because developers had a difficult time building anything particularly complex. Whatever the outcome, I'm excited for the ride.

16 comments:

Anonymous said...

Thanks for the useful article! You saved me hours of researching :-)

Anonymous said...

Thanks! Just what I was looking for!

Anonymous said...

While I agree there should've been better documentation, the API Demos would have been a perfect candidate for help in this situation. API Demos > Views > Progress bar.

fileoffset said...

Interesting aside:

I can find *no* clear way to instantiate a ProgressBar entirely programatically that is not indeterminate.

I like you just wanted a simple horizontal ProgressBar and have been through all the options twice, I am currently attempting to set all those methods you outlined as it being equivalent to in the hopes I can get it to work...

tek said...

Here is how to do this using code only, very VERY easy....

ProgressBar progress = new ProgressBar(this.parent, null, android.R.attr.progressBarStyleHorizontal);

fiXedd said...

One more on the "thanks" bandwagon here.

gunnar-mobimation said...

Wonderful, tek. I hate the XML way of doing it. I still vote for a RAD IDE that spits out programmatic UI's as back in the day. It makes for better average developer efficiency. The majority of ordinary developers would have been stuck for too long time figuring out this resource file way of accomplishing the progress bar.

Anonymous said...

Hi. It is useful article. Thanks.

Anonymous said...

s/archaic/arcane/

Dan said...

Hah! Thanks, Anonymous. You're absolutely right.

Unknown said...

i want to move from the progressbar page to another.for example-- when the progress bar stops it takes me to some another page where i wanna go...

Thanks in advance

From
Jimmy

Dan said...

Jimmy,

I don't know what your specific case is, but certainly somebody must be calling setProgress() or incrementProgressBy(). Whoever calls those methods could take responsibility for switching to another Activity.

guyvo said...

Yes agree on most things you said here although just started with android because of my new HTC phone ;-)
But xml provides a nice way to decouple most things related to the view with the actual code. But of course if there are no great IDE tools available to ease up that terrible declarative stuff developers wast their time on typing and reading the doc in depths. Sometimes even so hidden that one must browse the OS or framework packages to obtain the understandings. Eclipse has now a very rudimentary resource viewer but it can be much better. As we now reached 2.2 already things must be stable and ready to deliver some great aids in development.
Still I think there is must more opportunity in android than for instance javaFx on mobile platforms. I developed some javaFx mobile apps and believe me also far from ideal.
I hope we can expect some simplification tooling in the near future that will bring android to a fully valid development environment.

regards
Guy

sojan p r said...

Thnak you ma n .this saved a lot of time for me..

wingi said...

@tek: Thanx - here is an complete example of the programming solution: http://united-coders.com/nico-heid/show-progressbar-in-notification-area-like-google-does-when-downloading-from-android .

Nelson Glauber said...

Great explanation. Congrats! If you wantm visit nglauber.blogspot.com