Wednesday, June 26, 2013

Guava and minSdkVersion

A while ago I wrote about pre-dexing feature introduced at the end of 2012, which facilitates using large Java libraries like Guava for developing Android apps. Few months later, I'm still discovering stuff in Guava that makes my life easier (BTW: I still owe you a blog post with a list of Guava goodies). But this week, for a change, I've managed to make my life harder with Guava.

I wanted to include the javadocs and source jars for Guava, and when I opened maven central I saw the new version and decided to upgrade from 13.0.1 to 14.0.1. Everything went smoothly except for the minor Proguard hiccup: you have to include the jar with the @Inject annotation. At least it went smoothly on the first few phones I've tested our app on, but on some ancient crap with Android 2.2 the app crashed with NoClassDefFoundError.

The usual suspect in this case is, of course, Proguard. I've also suspected the issue similar to the libphonenumber crash I wrote about in March. When both leads turned out to be a dead end, I decided to run the debug build and to my surprise it crashed as well. And there was a logcat message which pinpointed the issue: the ImmutableSet in Guava 14.0.1 depends somehow on NavigableSet interface, which is available from API level 9. Sad as I was, I downgraded the Guava back to 13.0.1 and everything started to work again.

So what have I learned today?

  • Upgrading the libraries for the sake of upgrading is bad (m'kay).
  • Before you start wrestling with Proguard, test the debug build.
  • Android 2.2 doesn't support all Java 1.6 classes.


The scary thing is, the similar thing might happen again if some other class in Guava depends on APIs unavailable on older versions of Android. Sounds like a good idea for a weekend hack project: some way to mark or check the minSdkVersion needed to use a given class or method.

Thursday, June 6, 2013

SQLite type affinity strikes back

About a year ago I have wrote about a certain SQLite gotcha on Android. tl;dr: in some cases when you create a view with unions, SQLite cannot determine a type of the column, and since Android binds all selection arguments as strings, SQLite ends up comparing X with "X", concludes those are not the same thing and returns fewer rows than you'd expect.

Recently the same problem reared it's ugly head. It turns out that it's very easy to create in a view a column with undefined type. It might happen in case of joins, using aggregation functions, subqueries, etc. pretty much anything more fancy than simple select. Therefore I recommend checking the columns type using the pragma table_info(table) command for every view:
sqlite> .head on
sqlite> .mode column
sqlite> pragma table_info (v);

cid         name        type        notnull     dflt_value  pk
----------  ----------  ----------  ----------  ----------  ----------
0           test                    0                       0

If the type of a column is undefined and you need to use this column in your selection arguments, you should add the UNION with an empty row with well defined column types:
sqlite> CREATE TABLE types (i INTEGER, t TEXT);
sqlite> CREATE VIEW vfix AS SELECT i AS test FROM types WHERE 1=0 UNION SELECT * FROM v;
sqlite> pragma table_info (vfix);

cid         name        type        notnull     dflt_value  pk
----------  ----------  ----------  ----------  ----------  ----------
0           test        INTEGER     0                       0

Tuesday, June 4, 2013

MicroOrm API established

Last weekend I have found some time again to work on the MicroOrm. Basically it's something like google-gson for Android database types - Cursors and ContentValues.

With help from +Mateusz Herych and +Bartek Filipowicz I have, hopefully, finalized the API of the v1.0. The initial draft of the library supported only basic field types: primitives and their boxed equivalents and of course strings. The current version allows registering adapters for any non-generic types.

+Mateusz Herych added also the @Embedded annotation which allows easy nesting of POJOs which are represented by multiple columns.

Those two mechanisms should allow you to write the entity objects for almost any data structure you have.
The only unsupported cases are generic entities and generic fields in entities. I decided to leave them out of the first release, because due to type erasure in java the implementation is not straightforward and I don't have such cases anywhere in my code anyways.

The next step is using the library in the existing project. I intend to use it in Base CRM, which should be sufficiently large project to reveal any MicroOrm's shortcomings.

Wednesday, May 29, 2013

Android stuff you probably want to know about

About once a month I interview potential employees at Base CRM. The nice thing about this is that I usually learn a thing or two. The not-so-nice thing about it is that sometimes you have to tell someone that there is much they have to learn.

At this point most of the candidates ask "OK, so what else should I know?". I used to give some ad-hoc answer for this question, but it's not the best idea, because I tend to forget to mention about some stuff; and even if I don't miss anything, the candidate probably won't remember half of what I said because of the stress accompanying the job interview.

Anyways, I decided to write down the list of Android learning materials, blogs, libraries, etc. I recommend reading about.

Android basics

Some people's Android knowledge can be summed up as "Activities + AsyncTasks". That's not enough to write anything more complex than Yet Another Twitter Feed app, so if you seriously think of being the Android developer, go to http://developer.android.com/guide/components/index.html and fill the gaps in your education.

At the very least you should also know about Fragments and Loaders. If you want to persist the data, I recommend using the ContentProvider. It looks like a hassle to implement at first, but it solves all the issues with communication between Services and UI. While we're at the Services: you should know the difference between the bound Service and started Service, and you should know that most likely all you need is the IntentService. You should also know about BroadcastReceivers, and what is the ordered broadcast and sticky broadcast. Pay attention on what thread the different components operate.

Libraries

Support library
Guava
ActionBarSherlock
JodaTime
Commons IO
Dagger
Otto
Gson
HoloEverywhere

Blogs

Mark Murphy
Cyril Mottier
Romain Guy
Roman Nurik

Github

Jake Wharton
Square

Design / UI

Android Views
Android UI Patterns blog
Android Asset Studio
Android cheatsheet for graphic designers

Miscellaneous

Google I/O app sources
Grepcode
AndroidXRef

I probably forgot about something very important, so please leave the comment if you thing anything is missing.

Tuesday, May 28, 2013

Weekend hack: MicroOrm library

Last week I had to write some fromCursor() and getContentValues() boilerplate. Again. I finally got fed up and decided to write a library to replace all the hand rolled crap.

You may ask, why not use some existing ORM solution? There are plenty, five minutes with Google yielded these results:


The problem is, all those solutions are all-or-nothing, full blown ORMs, and all I need is the sane way to convert the Cursor to POJO and POJO to ContentValues.

And thus, the MicroOrm project was born. The public API was inspired by google-gson project and is dead simple:
public class MicroOrm {
  public <T> T fromCursor(Cursor c, Class<T> klass);
  public <T> T fromCursor(Cursor c, T object);
  public <T> ContentValues toContentValues(T object);
  public <T> Collection<T> collectionFromCursor(Cursor c, Class<T> klass);
}
I'd like to keep this library as simple as possible, so this is more or less the final API. I intend to add the MircroOrm.Builder which would allow registering adapters for custom types, but I haven't decided yet to what extent the conversion process should be customisable.

The elephant in the room is obviously the performance. Current implementation is reflection-based, which incurs the significant overhead. I did some quick benchmarking and it seems that the MicroOrm is about 250% slower than the typical boilerplate code. Sounds appaling, but it's not that bad if you consider that a) the elapsed time of a single fromCursor call is still measured in 100s of microseconds and b) if you really need to process a lot of data you can fall back to manual Cursor iteration. I'm also considering changing the implementation to use code generation instead of reflection, similarly to Jake Wharton's butterknife, which should solve the performance problems.

In the following weeks I'll try to adapt the Base CRM code I'm working on to use the MicroOrm, and I expect this project to evolve as I face the real-life issues and requirements. All feedback, comments, ideas and pull requests are more than welcome. You can also show the support by starring the project on Github.

Wednesday, May 22, 2013

Upgrading to Android SDK Tools revision 22

The Google I/O 2013 has come and gone and one of the many things left in its wake is the new revision of Android SDK Tools and ADT plugin for Eclipse. If you haven't let Eclipse go in favor of new hot Android Studio (which is what Mark Murphy, a.k.a. commons guy, recommends BTW) and you upgraded to the latest Android SDK Tools, you'll probably have some issues with building your old projects.

After installing all the updates from Android SDK Manager and updating the ADT Eclipse plugin your projects will simply fail to build, with the errors pointing to the R class in gen folder. If you try to build the project with ant you'll get more meaningful "no build tools installed" message. After re-running the Android SDK Manager, you should see an additional item in Tools section called Build-tools. Go ahead and install it.

Now your project will build (you might have to restart the Eclipse), but if you use any external libraries from your projects libs directory, your app will crash on the first call using this libs. To fix this you have to go to the project Properties, Java Build Path, Order and Export tab and check the "Android Private Libraries" item. The previous name for this item was "Android Dependencies" and apparently the build rules for those two are not updated correctly.

Of course new projects created with revision 22 of Android tools doesn't require jumping through all those hoops.

Wednesday, April 24, 2013

Android gotcha: CursorAdapter constructors

I just spend few hours analyzing and fixing a memory leak in Android application. With every orientation change the full Context, including the whole Activity was leaked. Long story short, the problem was caused by misuse of CursorAdapter: in subclass constructor we called CursorAdapter(context, null, false) instead of CursorAdapter(context, null, 0).

The difference is quite subtle. If you use the second constructor, you have to take care of handling content updates yourself. If you use the first constructor, the CursorAdapter will register an additional ContentObserver for you, but you need to manually reset the Cursor.

The funny thing is, this behavior is described in javadocs, but the documentation is spread between the constructor and FLAG_REGISTER_CONTENT_OBSERVER flag documentation. The second part contains most crucial information: you don't need to use this flag when you intend to use your adapter with CursorLoader.

If for some reason you want to use the adapter without CursorLoader, you should use the CursorAdapter(context, null, false) constructor, and call swapCursor(null) when leaving the Activity or Fragment.