If you have done any database work for Android by extending SQLiteOpenHelper, you have also had the experience of passing a Context down through the layers of your application to your database adapter. This is annoying because while you want the focus of your programming efforts to be on your application domain, part of your application design is focused on forwarding a framework-specific variable. Fortunately, roboguice comes to the rescue with just a few handfuls of code.
First, you’ll need to create an application class that inherits from RoboApplication:
public class MyApplication extends RoboApplication { }
RoboApplication contains the method protected void addApplicationModules(List<Module> modules)
that you can override and add any modules that you’ve defined to the List, so you can add the following to your application class:
@Override protected void addApplicationModules(List<Module> modules){ modules.add(new AbstractAndroidModule(){ @Override protected void configure() { requestStaticInjection(DBAdapter.class); } }); }
The method requestStaticInjection()
injects static fields that have the @Inject annotation into the specified class. Therefore, we can add the following to our database adapter class:
@Inject private static Provider<Context> contextProvider; private Context mContext; public DBAdapter() { mContext = contextProvider.get(); }
The last piece of the puzzle is for your Activities to extend from a Robo*Activity (RoboActivity, RoboListActivity, etc.) which will hook up the static injection:
public class MyActivity extends RoboActivity { }
Now, whenever an instance of the DBAdapter is created, roboguice will inject our current Context into contextProvider before calling the constructor:
DBAdapter dbAdapter = new DBAdapter();
Another way to inject a context provider into the DBAdapter is to use the usual guice injection strategy of creating an interface, implementing it, and configuring an AbstractModule. This approach requires more overhead, but perhaps creates a cleaner solution. I might write another post detailing this method if there’s interest.
Thanks to Donn Felker for clarifying some points.
Interesting post, I cannot get this to work, not sure if it’s something to do with the rest of my application, but I keep getting the infernal
ERROR/AndroidRuntime(9474): 1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access Key[type=android.content.Context, annotation=[none]] outside of a scoping block
Any thoughts? What’s this other approach you refer to?
Okay, just to answer my own question, I found that I had obviously been a bit too “clever” for it by adding:
bind(DatabaseHelper.class).asEagerSingleton();
removed this, and things all seem to be working now…..
Glad to hear you resolved it. I imagine you were getting that error because asEagerSingleton() creates the singleton when guice is initialized. Therefore, the DBAdapter is not being initialized from a Robo*Activity and a Context isn’t available.
I cannot find where to get javax.inject.Provider as this is not in roboguice-1.1-SNAPSHOT.jar nor in guice-3.0-rc1-no_aop.jar.
This appears to only be in the full guice distro. How can this work with just the android distro?
Hey Mick,
I’m currently using guice-2.0-no_aop.jar, and the Provider class is located at com.google.inject.Provider.