Mark Needham

Thoughts on Software Development

Learning Android: Roboguice – Injecting context into PreferenceManager

with one comment

In my last post I showed how I’d been able to write a test around saved preferences in my app by making use of a ShadowPreferenceManager but it seemed a bit hacky.

I didn’t want to have to do that for every test where I dealt with preferences – I thought it’d be better if I could wrap the preferences in an object of my own and then inject it where necessary.

Another benefit of taking this approach is that the interface of exactly what I’m storing as user preferences.

I wanted the class to be roughly like this:

public class UserPreferences {
    public String userKey() {
        return getDefaultSharedPreferences().getString("user_key", "");
    }
 
    public String userSecret() {
        return getDefaultSharedPreferences().getString("user_secret", "");
    }
 
    private SharedPreferences getDefaultSharedPreferences() {
        return PreferenceManager.getDefaultSharedPreferences(getContextHereSomehow());
    }
}

Initially it wasn’t entirely obvious how I could get a Context to pass to getDefaultSharedPreferences but I came across a blog post explaining how to do it.

What we need to do is inject a Context object via the constructor of the class and decorate the constructor with the @Inject attribute so that Roboguice will resolve the dependency:

public class UserPreferences {
    private Context context;
 
    @Inject
    public UserPreferences(Context context) {
        this.context = context;
    }
 
    public SharedPreferences getDefaultSharedPreferences() {
        return PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
    }
 
    public String userKey() {
        return getDefaultSharedPreferences().getString("user_key", "");
    }
 
    public String userSecret() {
        return getDefaultSharedPreferences().getString("user_secret", "");
    }
}

We never have to explicitly setup a binding for Context in our Roboguice because it’s already been done for us in RoboModule which is instantiated by RoboApplication which we extend like so:

public class TweetBoardApplication extends RoboApplication {
    private Module module = new RobolectricSampleModule();
 
    @Override protected void addApplicationModules(List<Module> modules) {
        modules.add(module);
    }
 
    public void setModule(Module module) {
        this.module = module;
    }
}

We then hook TweetBoardApplication up in the AndroidManifest.xml file like this:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pivotallabs"
          android:versionCode="1"
          android:versionName="1.0">
    <application
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Light.NoTitleBar"
            android:icon="@drawable/app_icon"
            android:name="TweetBoardApplication">
   </application>
</manifest>

And that’s it!

Be Sociable, Share!

Written by Mark Needham

January 12th, 2012 at 5:24 pm

Posted in Android

Tagged with