Monday, November 21, 2011

ActionBarSherlock and RoboGuice can be friends

The ActionBar

In Android applications, the ActionBar is quickly emerging as a UI standard. Although its great, the ActionBar is only supported on Android 3.0 (API level 11, aka Honeycomb) and later. Since (either from prudence or incompetance) carriers seem to push new versions of Android out rather slowly, the majority of phones running Android are on 2x.

ActionBarSherlock and RoboGuice

There's a problem then, the ActionBar is nice, but only a small percentage of phones support it. Luckily, lots of smart folks have created ActionBar libraries for pre-3.0 Android, my favorite is ActionBarSherlock. ActionBarSherlock's API is identical to the native 3.0 ActionBar, and if the native ActionBar is available, ActionBarSherlock politely steps aside and uses it.

Another necessity, at least for me, when developing non-trivial applications is a dependency injection framework. DI frameworks are a big help, allowing me to attack large problems with a set of simple, testable, classes which collaborate but are not coupled. For Android, I'm currently using RoboGuice a popular extension of Google's Guice dependency injection framework. RoboGuice also ships with a nice set of classes easing some of the more annoying parts of developing Android apps. The problem is:

These libraries don't work in the same app

To make ActionBarSherlock work as well as it does, it includes the compatibility library and patches a few of the classes in it. A few of RoboGuice's classes such as RoboListActivity and RoboFragment extend classes from the compatibility library but not the ActionBarSherlock-patched compatibility library. The good news is that these libraries are solving different problems, and we can attack the DI side of the problem using RoboGuice and composition.

Here's a simple solution: extend the ActionBarSherlock-patched compatibility classes and get injection via composition using RoboGuice.getInjector().
You can now extend from IocListFragment (or any other class you need to create in this way such as IocFragment) and get @Inject along with a nice ActionBar:Fortunately you'll only need to extend a few classes in this way to make both of these libraries work in the same app. This solution feels a bit clunky, so if you know a better solution to this problem, please share it.

2 comments:

Jake Wharton said...

I'm surprised to hear that this didn't "just work" with the RoboGuice 2.0 jar and ActionBarSherlock as a library project. ABS was meant to seamlessly replace the official compat library with little-to-no code changes (which only deal with Menu/MenuItem incidentally).

If you are using maven you can use the <excludes> specification on the RoboGuice dependency to remove its transitive dependency on the official compat lib. Then ActionBarSherlock 3.x should fulfill that requirement since its classes exist in the same package. This was reported to have worked on the Google Group for ABS.

I haven't yet had time to experiment with implementing both of these libraries in the same project (yet!) but hopefully the coming changes to ADT and library projects will allow the inclusion of both to be much easier.

After all, it is without a doubt a winning combination.

Max said...

Hey Jake,
Thanks for the info, resolving this when building sure beats writing a few awful one-off classes. I'll give that a shot and edit my post with the results.