Sunday, May 23, 2010

Android: Serializable Considered Harmful

This is an old problem, but anyone I can convince not to use Serializable on Android will help the system as a whole.

There is some data saved between launches of my application - a list of complex objects. When I first learned Android I assumed that the fastest way to get the app up and running would be to slap Serializable on my data classes and call it a day. It certainly got things up and running quickly, but with some serious performance issues. I never noticed this in early testing because I only saved a few objects at a time. However, when I got up to 5+ objects the system started to slow down, and at 10+ it ran like molasses. There's not normally that many objects, but it's still something to be concerned about. It's not like I was doing anything complex, however - it was simply that Serializable is that slow.

Not only that, but I had to live in constant fear of changing the data structure. If enough things changed I would have to write my own serialization processes to work with backwards compatibility. Yuck.

I switched to using JSON to store all my data and this decision has made my life so much better. Android comes with a good JSON library and it's pretty simple to add JSON support to classes. JSON is much, much faster than serialization and comes out with much smaller results, too (you can even GZip the results to make them smaller still). To put it in perspective, the save time is now unnoticeable, whereas I could count the seconds using Serializable; and the file size was reduced by an order of magnitude.

Not only is it better for saving data, it's a very easy way to pass data between components. When I first started, I saw three ways to pass data between components: Serializing, parceling, or storing data in the Application context. Serializing was proving too slow, parceling is really a pain in the ass, and the last solution is harder to integrate with later on (no one else can call your component). JSON has proven a much better solution - it's fast enough to get by, but not nearly the pain in the ass that Parcels are.

Monday, May 3, 2010

ViewFlipper "Receiver not registered" Error

There is this error that plagued me for a few months. If you use a ViewFlipper, this error will pop up on Android 2.1 devices every once in a while:

java.lang.IllegalArgumentException: Receiver not registered: android.widget.ViewFlipper$1@44b6ab90


It does not affect any devices before 2.1, and so what was troubling at first was that the 2.1 source code wasn't yet released so I could't diagnose the issue. Everyone knew it had to do with orientation changes on an Activity with a ViewFlipper, but why exactly it happens isn't clear (I took my own stab at it, but was incorrect about the exact cause; it just seems to happen randomly).

Thankfully, the source has been available now for a while. Obviously, the problem is that onDetachedFromWindow() is somehow being called before onAttachedToWindow(); but how do we come up with a workaround until it is fixed at Google?

One simple solution is to override onDetachedFromWindow() and catch the error from super:

@Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
}
catch (IllegalArgumentException e) {

}
}


The only problem with this is that the error is thrown before calling updateRunning(). A simple workaround for this is to call stopFlipping(), as that will kick off updateRunning() without any negative side effects:

@Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
}
catch (IllegalArgumentException e) {
stopFlipping();
}
}


You should only use this version of the class on Android 2.1 phones, as they are the only ones requiring the fix.

EDIT May 25, 2010: ViewFlipper bug still occurs in Android 2.2. I sure hope you didn't filter based on apiLevel == 7; better to use apiLevel >= 7.

Why They Can't Find Your App

The Android Market is a mixed blessing; on the one hand, I much prefer the near-instantaneous publishing time for applications. It makes things a lot less stressful; if there's a terrible bug you can fix it quickly instead of having to go through Apple's approval process all over again. On the other hand, it has a number of bugs and limitations that are frustrating.

One of the most common support emails I get is "why can't I find your app on the Market?" This is a sad email, one of a customer lost; and over time (from contact with Google or perusing the net) I've come up with a good list of reasons why customers can't find my applications. Here it is, to help others diagnose the dreaded customer-who-would-be (in order of most likely to least likely):

1. The customer has an older version of Android that your app does not support; for example, if you support 2.x but the user is on a 1.5 phone.

2. Paid apps are only supported in some countries; if the customer is not in one of these countries, then you will not be able to find or purchase any paid applications. The list of supported countries can be found here.

Note that the customer can't simply move to a different country, either; this limitation is dependent on where your phone plan originally comes from. (Thanks to a European customer who confirmed this for me on a business trip!)

3. The customer is using a Google Apps account, rather than a gmail.com account. This can either cause the app not to appear at all, or in some cases make it unpurchaseable. More details can be found here.

4. The customer has a recently released phone and Google hasn't "fingerprinted" that device yet. This blocks all paid apps from that device. The only solution is to wait until Google fingerprints; it was kind of a pain with HTC Desire, at it took them a few weeks to get around to it.

5. The customer is using a non-standard build of Android (that is, rooted and installed a custom ROM). Some of these builds cause the Market to malfunction and fail to display paid apps.

6. The customer is using an Android Developer Phone and your application has copyright protection enabled. ADPs aren't allowed to view copyright protection applications. More info here.

7. This is by far the least likely situation, but you can't buy your own app under the same account as you published from!