5 articles Tag development

Example of custom states in Android components

A while ago, I built a form based app with lots of input fields and all the things that come with that, like validation and error messages.

In one of the situations, if a section is invalid, the field labels should turn red. Easy right? Here’s the example layout:

And a naive way to switch the label colors when there’s an error:

But this is kinda ugly. We need to get “not-error” color from each component, store it, switch the color to red and if the error is fixed, restore the colors again. There’s too much code that deals with updating the view in here and it only gets worse if we add more labels.

Using selectors

You’ve probably worked with selectors before. In this particular case we’ll be using a ColorStateList selector to change the color of the TextView. First, here’s the selector:

This is just like any other ColorStateList xml. You place it in the res/color/ folder of your project. This selector has one thing extra though: the app namespace and the app:state_error state. In effect this selector says:

  • If the state is error the color used is color_error as defined in color.xml
  • If the state is pressed, for example if the TextView is clickable and you click on it, the color used is color_pressed
  • By default the color is default_color

By know you probably see where I’m going…If we can change the state of the TextView to app:state_error then the color should be set by the Android framework to the color_error that is defined. But how do we do that?

First we have to actually define the new state in res/values/attrs.xml:

Then we should actually apply that state. We can do that in two ways:

  1. Extend TextView
  2. Extend the LinearLayout containing the TextViews

In this case we’ll extend the LinearLayout like this:

This code should be easy to follow. We add an extra property mError to keep track of the error state. At line 3 a constant is defined containing an array of states that are set when mError is true. Then it’s just a matter of overriding onCreateDrawableState() which takes an int called extraSpace. Since potentially we’d like to add one extra state if the mError flag is set, the code calls super.onCreateDrawableState() with extraSpace + 1. Then, depending on the mError flag the error state is added to the list of states.

The final layout using this new component looks like this:

Things to notice in this layout:

  • In stead of LinearLayout, ErrorStateLinearLayout is used as the main container
  • Each TextView has android:duplicateParentState=”true” meaning that the TextView will inherit any states from the parent view group.
  • Each TextView has it’s textColor set to error_color which would be the color state selector

Now we can finally update the view when there’s an error like this:

Much cleaner code, less bugs, yay for us!

Conclusion

By leveraging core Android principles, in this case using selectors, we can simplify our code a lot. By moving things that are related to the view out to xml resources not only our code gets cleaner, but we could also use the resources system to customize the ui based on the device configuration.

PS: ViewGroup has android:addStatesFromChildren which is equally useful!

Comment on this post on Google+

Android Ant dependency management

Here’s a crazy idea I had yesterday: poor mans dependency management for your Android ant (and Eclipse) builds.
I could of course use maven, but I don’t. TL;DR; I think it’s too much hassle for my Android projects. I pull in library projects from source using mercurials’ subrepository feature and check the libs folder in to source control.

Anyway, I do like the dependency management part of a maven build, although I also might have some local dependencies that I just want to stick in my project and check in. So the idea was to hook in some form of dependency management into the normal Android ant build. Another requirement is that it should work fine with ADT. What I’ve come up with in the last few hours is here: https://bitbucket.org/hvisser/android-ant-dependencies and here on github: a build file that you can include into your normal ant.xml.

It uses the maven tasks for ant to manage dependencies. What this build file does for you when you execute “ant copy-dependencies” is manage the dependencies in the “libs” folder of your project. If you have non-managed jars, you just stick those in the “extra” folder. It will also extract library projects, apklibs, to a separate folder so you can include those as library project in Eclipse. Finally, it will copy over android-support-v4.jar to those library project, to make sure you are using the same version in all projects (the Android ant build and ADT check for that).

When setup, you can ignore the libs folder in your favorite version control system and on check out you just to a “ant copy-dependencies”, import the library projects and off you go.

Now I don’t know if I’m actually going to use this, but what do you think? Have I created a monster?

Please comment on the Google+ post

Correct Intent to compose an email on Android

Starting a compose window to write an email in your favorite email client on Android is easy.
It amazes me however that when you search for it on stackoverflow most first hitters are suggesting to use an intent with the mime type set to text/plain (or worse) See http://stackoverflow.com/questions/6450097/how-to-send-email-by-clicking-text-view-links/6450131#6450131http://stackoverflow.com/questions/7551600/how-can-i-send-an-email-through-my-exchange-activesync-mail-account or here http://stackoverflow.com/questions/10546252/unable-to-send-email-from-android-application-on-real-device for example.Being an intent, that code expresses that you like to perform a SEND action on ANYTHING that can handle text/plain or whatever mime type. So apps like Dropbox etc will rightfully also pop up.What you really want is to use a mailto: uri in the data, since that expresses that you want to….MAIL TO SOMEBODY. So you set up the intent like this:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("mailto:hugo@googleplus.com"));
// you can add extra's like subject, text, etc

I’ve been using this for ages (since Android 1.5) and it should work fine. Of course your favorite mail app should register for the mailto scheme, but I’m sure any decent mail app will.

I did find an answer on SO that actually mentions this, not all hope is lost: http://stackoverflow.com/questions/2007540/how-to-send-html-email

Don’t use text/plain if you want to send an email. A droid will die every time you do :(

A little tool for handling nine patch files, called 9tool

Here’s a little tool I wrote for handling 9patch images called 9tool. If you work with (a lot) of nine patch files in Android, you might find it handy too.

  • My workflow currently is something like this:
  • Get the xhdpi asset and make it a nine patch using draw9patch
  • Get the other states for the asset and do a 9tool copy on it to copy the nine patch area to those assets, then load those in draw9patch for some touch ups.
  • Now get the other assets for other dpis. 9tool copy the patches I made from the xhdpi assets to the other dpi variants, touch up using draw9patch again.

This saves me a bunch of manual drawing in draw9patch and makes me a happy camper!

The code is open source and as much in the public domain as it can be, so do with it what you like. I’ve only spent a couple of hours on it so there might be many bugs and it might be a bit messy. So far I haven’t lost any 9patches in the process though ;)

There’s a zipped build in the downloads section if you don’t want to build from source.

The tool is hosted on bitbucket here: https://bitbucket.org/hvisser/9tool

Android Logging

Logging in any type of software is a useful tool to debug and improve your software. Typically you’ll have different types of stuff you want to log: errors, information, traceing etc. So most logging systems have a concept of levels that allow you to specify how important a message is, so that at a later time you can enable a certain type of logging to inspect.

In Android it is handled by the Log class. It too allows for runtime configuration of loggers and it involves setting Android system properties using the setprop command, which is nice if you are building an app as part of the OS but maybe overkill or even clunky if you just want to create your next great app. And what if you don’t want your shipping app to have any logging whatsoever? You certainly want it during development, trust me :) Well enter this little utility class:


package com.neenbedankt.rainydays.util;
public class Logging {
    public static final boolean LOGV = true;
    public static final boolean LOGD = false || LOGV;
    public static final boolean LOGI = false || LOGD;
    public static final boolean LOGW = false || LOGI;
    public static final boolean LOGE = false || LOGW;
}
 
What this does is setting some flags that indicate what level of logging you want. If you want all logging, just set LOGV to true. If you only want the “info” level and up just enable info. Easy! Now you still have to reference this from your code like this:


// you can also use a static import to drop the Logging part...
if (Logging.LOGD) {
 Log.d(TAG, 'This is my debug statement');
}

Tip: you can setup an Eclipse template to generate these kinds of code blocks very fast.

Now the beauty of this all is that since the LOGD variable is a static final (a constant) the compiler will strip out the entire if statement if the LOGD variable is false, hence no logging in your final app and no bytecode generated for it either.

So by introducing a simple class and wrapping the log statements in an if block you’ll still be able to enable particular levels of logging, while in your shipping product the logging is stripped out.