Manage Android state with bundles @Frozen

This morning this post showed up in my stream by +Philippe Breault. About the caveats when treating the Application object as global state.

Although the advice that he gives, don’t store stuff in the Application object, is sane the example doesn’t really illustrate the problem. His argument is that when the activity is recreated, the application is recreated and therefore the state is lost. While this is true, the real issue is that the GreetLoudlyActivity from his example isn’t saving any state, which it should.

Luckily, this is easy to fix! A little while ago I wrote bundles, a set of two annotation processors for Android. The @Frozen annotation makes it easier to save and restore state in Activities and Fragments. So let’s fix the GreetLoudlyActivity:

class GreetLoudlyActivity extends Activity {
TextView textview;
@Frozen
String mName;
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reading);
textview = (TextView) findViewById(R.id.message);
// because we are still referencing the global application singleton, that may not be initialized,
// we need this null check to see if the activity is restored
if (savedInstanceState == null) {
MyApplication app = (MyApplication) getApplication();
mName = app.getName().toUpperCase();
} else {
GreetLoudlyActivityState.restoreInstanceState(this, savedInstanceState);
}
}
void onResume() {
super.onResume();
// removed the reference to getApplication from onResume
textview.setText("HELLO " + mName);
}
void onSaveInstanceState(Bundle outState) {
// this class is generated by the @Frozen annotation
GreetLoudlyActivityState.saveInstanceState(this, outState);
}
}

If you don’t want to use custom code for it, this is how you would do it without @Frozen:

class GreetLoudlyActivity extends Activity {
TextView textview;
String mName;
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reading);
textview = (TextView) findViewById(R.id.message);
// because we are still referencing the global application singleton, that may not be initialized,
// we need this null check to see if the activity is restored
if (savedInstanceState == null) {
MyApplication app = (MyApplication) getApplication();
mName = app.getName().toUpperCase();
} else {
mName = savedInstanceState.getString("name");
}
}
void onResume() {
super.onResume();
// removed the reference to getApplication from onResume
textview.setText("HELLO " + mName);
}
void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("name", mName);
}
}

Remember, there’s a setting in the development settings section of your phone (ICS or up) to test for these kinds of bugs. It’s the “don’t keep activities” option.

Introducing Cupboard: simple persistance for Android

Today I’d like to introduce you to a new library that I’ve been building and using at Qbus in various apps for over a year called Cupboard.

Cupboard is what I’d like to call simple persistence for Android. Most non-trivial apps need some kind of persistance, most likely using a SQLiteDatabase. There are already many libraries and frameworks like ORMLite that are populair choices, but after evaluating most popular options we decided to take a different path.

Background

Basically, I built Cupboard out of frustration with the available options. I don’t like frameworks that take over my code: require me to extend an interface for models or force me in to a global DAO / EntityManager kind of approach. I needed something that I could easily integrate with what Android already gives me. Things like SQLiteDatabase, Cursor, ContentValues. I especially needed something that could work in multiple contexts: passing data from/to a ContentProvider from an Activity for example. None of the options I looked at totally satisfied me in that regard.

For Cupboard I set out to achieve the following goals:

  • Persistence of Java Objects, no more ContentValues and Cursor.getColumnIndex()
  • Simple and lightweight
  • Not a framework, but a library, like syntactic sugar.
  • Integrate with core Android classes without any hassle

Let’s also mention what Cupboard isn’t: it isn’t a full fledged ORM solution. For example: while you can hold references to other entities, the relational aspect isn’t managed by Cupboard. This makes things simpler and we haven’t missed it in our apps so far.

How does it look?

An entity is a very simple object, with their field names corresponding to the columns of the table they are stored in. Remember, field access is fast in Android.

public class Person {
 public Long _id;
 public String name;
 public int age
}

Here’s a line of code from a CursorAdapter to bind to a Person object from a cursor

Person person = cupboard().withCursor(cursor).get(Person.class);

Here’s how you’d get a person with id 12 from a SQLiteDatabase:

Person person = cupboard().withDatabase(db).get(Person.class, 12L);

Or using a ContentProvider:

Uri uri = ... // the uri to Person object we want to get
Person person = cupboard().withContext(mContext).get(uri, Person.class);

Note that the cupboard() function is just a helper; it holds the Cupboard instance that knows about your entities. You could inject the instance if you are using a dependency injection framework.

The Cupboard instance doesn’t hold on to your database, it doesn’t manage anything. So if you would need to interact with the cursor in the first case, or the database in the latter case, no problem! Pass in a different database? Sure!

Using Cupboard

Cupboard is Open Source software, Apache Licensed like most Android libraries. You can get it at the project site. Check out the documentation to get started or look at the sample project. You can add it to your project as a simple jar. There’s a pre build jar on the project site as well. The jar includes the source for easy debugging.

I’m curious if you think this is useful to you too. Let me know on Google+ or Twitter!

Bundles 1.0.2

Minor update to bundles, my annotation processor for Android source code to help constructing fragments and saving state.
I’ve been sprinkling these annotations in my existing projects and fixed a few small issues.
  • The generated FragmentBuilders now get a newFragment() method useful if you want to construct a fragment with only required arguments
  • The required args are sorted now, so that the builders are consistent when you add, remove or recompile the source class ;)

You can get it here: https://bitbucket.org/hvisser/bundles or from github here: https://github.com/hvisser/bundles

View this post on Google+

Android Fragment builder annotation

Since annotation processing is the new hip thing to do, I thought I’d jump on the bandwagon ;) Yesterday I wrote two annotation processors to make my life simpler. It doesn’t have a spiffy name like +Jake Whartons butterknife, but hey, you can’t have it all.

The first one deals with Fragment instantiation and arguments. As you might be aware, a Fragment needs to be instantiated with a Bundle to pass the arguments. That usually leads to a static newInstance method where you marshal the passed arguments into the arguments bundle, instantiate the Fragment and set the bundle on it. Using the @Arguments annotation, this process is a lot easier. You just annotate your fields and from that information a <YourFragment>Builder class is generated. The builder can be used to construct the fragment in a type safe way, and it has a static method to “inject” the arguments into the fragment at your convenience.

The second annotation is @Frozen. This annotation generates a <YourClass>State helper class that will save the fields annotated with @Frozen to a bundle or set the fields on your target object. This is very useful in onSaveInstanceState and OnCreate etc.

The code and jar download is on bitbucket here: https://bitbucket.org/hvisser/bundles and is in the public domain. It’s not yet field tested, so be aware that there might still be some subtle bugs. Yes I’m just throwing it out there, hoping that it’s useful to you.

View this post on Google+

New updates for Rainy Days: Hello Australia!

I just released a new update of Rainy Days, my radar weather app for Android. This version adds a few new features that have been requested and adds Australia to the supported countries as well.

Here’s a list of the new stuff:

  • Animation length adjustable: you can now select short, normal or long lengths for the animation. Shorter will load faster, while long will show you more frames.
  • New gestures: swipe from bezel to quickly scrub through the animation, double tap, hold and up/down to zoom (like in the Maps app).
  • If your location is shown on the map, and you are moving, the map will now move too so you don’t need to scroll yourself
  • Other fixes and tweaks (performance, battery usage, etc).

I’ve also created a small video demoing the gestures:

As always, you can dowload Rainy Days from the Google Play Store, enjoy!

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

DPI Hell

Yesterday the DroidconNL conference started with a keynote from greetz.nl called “Pushing Development Boundries”. After some introductory talk from their marketing manager, this slide appeared on screen:

Dpihell

To which I responded:

I realise that might have sounded a bit harsh, so let me explain and give you some background. The last year I’ve been talking about “Embracing Fragmentation” at mdevcon, Mobile Down South and Apps World. The talk is about the challenges and opportunities developing and designing for the Android platform and showing what mechanisms are there to make it easy to deal with the “problem” of fragmentation, which honestly in my opinion as a professional Android developer, isn’t as huge as some people would like you to believe.

To me “hell” in the context of software implies something that is hard, complex, unpredictable, fragile and whatnot. Resolution and DPI on Android do not fall in this category for me. If you qualify these things as “hell” and you’re a professional Android developer, I think you need to read the rest of this post.

What’s this DPI thing anyway?

DPI is short for dots per inch, also known as pixels per inch or PPI. On iOS Apple calls things with a high PPI count “retina” to indicate that you can’t see the actual pixels on a screen since they are so close together that your eyes, or your retina, can’t see the individual pixels. In a way DPI tell you about the quality of a screen. Generally, when comparing screens of the same size, higher is better.

Now what’s the deal with resolution and DPI? Let’s say you have a 4 inch screen and a resolution of 1200×800 pixels. At the same time imagine a 10 inch tablet screen at 1200×800 pixels. Which screen would have the highest DPI? The 4 inch screen, since it literally packs more pixels / dots per inch. Get it? When designing a user interface this is important, for two reasons:

  1. You want your stuff make look good on any screen.
  2. You want your stuff have the same size on any screen.

How do we generally measure things on screens? Pixels. This works fine when all screens have the same DPI. Let’s say a screen has 100 dots per inch. That would mean that a line which is 100 pixels wide, would measure 1 inch exactly. Simple right? Now what happens if you draw that same line on a large screen, with the same resolution? There are less dots per inch, for example 50, so all of a sudden your 100 pixel line is now 2 inches wide. Not good!

On Android (and iOS for that matter) you don’t deal with pixels as the unit of measuring things. You deal with density independent pixels, or dips for short, or dp for even shorter. On iOS you’d call them points by the way. What measuring in dips gives you is a consistent unit that takes into account the DPI, which becomes essentially a scaling factor. Let’s say we’d call 50 dpi our “baseline” dpi at which 50 dips is exactly 1 inch. To make it show the same size on a 100 dpi device, we would take the scaling factor (twice the amount of pixels per inch) and draw it at 100 pixels, which would give us the same sized line. Why? Because 100 is twice 50, so our scaling factor is 2 and because 100 pixels at 100 dots per inch would be exactly 1 inch again. Confusing? Maybe, but the thing to remember is: you don’t deal with pixels. You tell the Android how large a thing should be in dips and Android will take into account the appropriate scaling factor, figure out the right amount of pixels and will make sure the thing you are drawing to the screen is the same size no matter what screen your app is running on. Same for iOS: you tell the OS how large the thing you are drawing to the screen is in points, the OS figures out how many pixels that would be for the screen (either the same amount or twice the amount for retina screens) and it will look the same size, no matter if you are running on a retina screen or a non-retina screen.

So that leaves us at DPI hell. I guess what the speaker was referring to is how to make your stuff look good on any screen. First of all, it’s good to know that Android currently has 5 DPI “buckets” that are relevant to developers. In order of lowest to highest DPI they are called ldpi, mdpi, hdpi, xhdpi and xxhdpi. As a contrast, iOS has two buckets: either non-retina or retina.

Like I said there’s a scaling involved when an app runs on various screens. Scaling stuff you draw yourself at runtime is usually not the issue. You are rendering that stuff when the app runs so things will always look good. But what if you include an image and that image should be scaled up or down to make it the proper size for the given dips and DPI?

In that case you have two options:

  1. You supply the image at a particular DPI and let Android deal with the scaling from that bucket to other buckets at runtime
  2. You supply a scaled version for one or more DPI buckets

One strategy could be to only supply the assets for the xhdpi bucket and let Android take care of the scaling. Depending on your assets and the version of Android you are targetting this might work fine. Usually though you need some tighter control over how images are scaled. A common strategy would be to supply assets for the mdpi, hdpi and xhdpi bucket and aditionally a launcher icon for the xxhdpi bucket. Since ldpi devices are rare, the Android platform would take care of scaling to ldpi by conveniently scaling down the hdpi asset by a factor of two. Likewise assets for the tvdpi bucket (hey! you said there we’re only 5 buckets! – I lied) should generally look fine when scaled by Android.

So you might be thinking: “wow, duplicating my assets for 3 different buckets AND creating 4 launcher icons seems like a lot of work”. Yes, it is. But I most certainly wouldn’t call it hell. Besides there are some great tools which help you to reduce the amount of work you need to do and Android has more mechanisms to reduce the number of bitmap assets in your project anyway.

One question remains: if it’s not hell, how should you approach this then? Here’s something that generally works when designing and scaling assets if you know the size in dips:

  1. Design your asset doubling the size in dips. If your image is 100×200 dips then in pixels you design it at 200×400 pixels. This is your xhdpi asset. This works because at xhdpi one dip is exactly 2 pixels, meaning the scaling factor is 2. At mdpi one dip is one pixel which is equally handy.
  2. Scale this asset down by 75%. This is your hdpi asset.
  3. Scale the xhdpi asset down to 50%. This is your mdpi asset.
  4. Put the assets in the correct resources folder within your project: drawable-xhdpi for xhdpi, drawable-hdpi for hdpi, drawable-mdpi for (yes!) mdpi.

I recommend starting from the highest DPI you need to the lowest, since scaling down from a higher resolution usually gives better results than scaling up from a lower resolution. I also recommend that for launcher icons, you use the excellent Android Asset Studio combined with an icon in svg format which will spit out the launcher icons in all DPI variations without even bothering scaling it yourself in your favorite asset creation tool.

Phew, that was a lot of text, just to explain it’s not hell, but seriously: if you are an Android developer you should know the rules to play by. If you know them, then making your apps look great isn’t hard. There’s a lot of information on the subject at d.android.com, for example on supporting multiple screens, which I encourage you to read.

I hope you found this post useful, please leave any feedback in the comments, Google Plus or tweet at me. Thanks!

Note to self: ListFragment and header views

While hacking on our FOOD! app for VHack Android I ran in to an issue.

FOOD! shows a couple of ListViews through ListFragment that have a header (the title) set on them. That all works pretty cool, but if I tried to add multiple ListFragment on the back stack it would crash on pressing the back key, with this exception:

java.lang.IllegalStateException: Cannot add header view to list — setAdapter has already been called.

The code for my ListFragment looks something like this:

package com.neenbedankt.listfragmentbug;
import android.annotation.TargetApi;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class TestListFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView tv = new TextView(getActivity());
tv.setText("Hello");
getListView().addHeaderView(tv);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,
new String[] { "Hello world" }));
}
}

The code crashes, because when you press back, the view is recreated through onCreateView and aparently the list is in some state that I’m not allowed to add the header.

So the big question is: WHY? First thing that popped to mind is that the ListView itself was recycled and somehow retained. This is not the case: if you debug ListFragment you’ll see that the ListView itself is null and the view is inflated.

The issue is that ListFragment will set the adapter on the ListView as part of it’s private ensureList() method that get’s called in onViewCreated. In most scenarios you would set up your adapter after creating the view add add it using the setListAdapter() method in the ListFragment (note: not on the ListView itself!). ListFragment keeps the adapter in a private member so that you could create the adapter before the list itself is created and everything would still work.

Now when you replace the fragment, the Fragment view is destroyed, but your ListFragment is still in memory, on the back stack. When you press back, that instance is used again and it’s life cycle methods like onViewCreated get called again. Then, as part of the ensureList() call, the adapter get’s set on the ListView (which is non-null now) and if you attempt to add a header view at that point…BOOM.

Fortunately there is a workaround for this: clearing the adapter when the view is destroyed, so that there won’t be an adapter to set when the view is recreated.

package com.neenbedankt.listfragmentbug;
import android.annotation.TargetApi;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class TestListFragment extends ListFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView tv = new TextView(getActivity());
tv.setText("Hello");
getListView().addHeaderView(tv);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,
new String[] { "Hello world" }));
}
@Override
public void onDestroyView() {
super.onDestroyView();
setListAdapter(null);
}
}

So one question remains: bug or feature? Keeping the adapter can be a good thing, since it will make the list show stuff when hitting back, no need to load or wait for the loading. You could even test if the adapter is non-null and skip loading all together. On the other hand, the fragment initialization is now different depending on if it’s newly created or if it is an existing instance coming back to life, which is bad thing. The root cause is that you can’t add a header view after the adapter is set, because ListView wraps the adapter you set in a special adapter for showing the headers, so you could argue that ListView is broken in that sense. I personally think it’s a bug. If I wanted to optimize and keep the adapter, then it would make sense to keep the adapter in a member variable that I control. Now it is done “under the covers” and you have to know the implementation details to fix the issue.

In any case, I hope this write up will help others running into the same issue, happy coding!