Saturday, September 3, 2011

How to inject context in Android with and without RoboGuice?

If you want have cleaner separation in your Android app, you definitely need to move your logic to classes other than Activity, like you do in any GUI patterns. When you try to do that, first obstacle you would face is lack of access to Context class. Context lets you access resources and controls in the Activity. You can achieve this with or with out a Dependency Injection tool.

One of the simplest and easiest way is to pass the Context around, Take a look at line# 7, I am passing application context not Activity’s context to avoid memory leaks. Only pass Activity’s context when its necessary and keep your eyes open for smelly code. This is not the greatest approach, but it will get you going fast. Be aware, you are opening up yourself  to lot of repetitive code and potential memory leaks.

Another approach is, lets not pass the Context around, use Service Locator anti-pattern to resolve the Context. Little bit less code and we can’t pass around Activity’s context. But we made testing our code harder then before. Now you have to have another constructor to inject Context or have to mock the MyApplication class to provide testable Context.

Notice we are not passing context to the utility class, we are just creating an instance of the utility class. MyUtility class gets the application Context using some bare bone service locator,

Here MyApplication extends from Application and holds a static reference to itself. Don’t forget to set the Application name as MyApplication in manifest.xml file as described here.

Now lets see a cleaner approach using Robo Guice,

Install and wire up Robo Guice as suggested here, Lets take a look at our Application class, We are extending our application from RoboApplication. This is going to act as our IoC container.

Now we need a module to configure our injections. This module holds the injection map. Think this map as a way Robo Guice decides how to create classes for a particular type. See we haven't configured any mapping for Context, Robo Guice has built in mapping to resolve Context and Application.

Now lets take a look at out utility class, it has nothing interesting except the @Inject attribute, it tells Robo Guice to use this constructor to create MyUtility and resolve all the parameters.

Lets take look at the final piece of the puzzle, Activity class, Take a look at how cleaner it is, No cluttered onCreate method no nasty castings of controls. It is much more readable and less code. Robo Guice finds all the members with @Inject attribute and injects necessary types.