2

I've been playing around with Transfuse (http://androidtransfuse.org/) and am now trying to tackle SharedPreferences. The documentation makes this seem pretty straight forward:

@Activity
public class Example{
    @Inject @Preference(value = "favorite_color", default = "green")
    String favColor;
}

However, as I understand it, SharedPreferences are retrieved by name, not just by key. So, how does Transfuse know the name of the SharedPreferences file I'm trying to access?

I've tried something like this to no avail:

@Activity
public class MainActivity{
    public static final String PREF_NAME = "pref_name";

    @Inject
    android.app.Activity mActivity;

    @Inject @Preference(value = PREF_NAME, defaultValue = "")
    String mPreference;

    @Inject @View(R.id.preference)
    EditText mPreferenceEditText;

    @RegisterListener(R.id.button_2)
    android.view.View.OnClickListener mSavePrefListener = new android.view.View.OnClickListener() {
        @Override
        public void onClick(android.view.View v) {
            String val = mPreferenceEditText.getText().toString();
            mActivity.getSharedPreferences("the_shared_prefs", Context.MODE_PRIVATE)
                .edit()
                .putString(PREF_NAME, val)
                .apply();
        }
    };

    @OnResume
    private void displayPrefText(){
        mPreferenceEditText.setText(mPreference);
    }
}

Thanks for your help!

Justin Pollard
  • 6,661
  • 1
  • 18
  • 20
  • 2
    Presumably, it is using `PreferenceManager.getDefaultSharedPreferences()`. – CommonsWare Jul 17 '14 at 00:16
  • @CommonsWare looks like you're right about that! Is there anything about the default shared preferences that make it less desirable than getting a shared preferences file by name using Context.MODE_PRIVATE? – Justin Pollard Jul 17 '14 at 00:31
  • IMHO it is more desirable, as `getDefaultSharedPreferences()` is the `SharedPreferences` used by default by `PreferenceActivity`. The only time I use an alternative `SharedPreferences` is from some library, so I don't collide with any `SharedPreferences` in use by the hosting project. – CommonsWare Jul 17 '14 at 00:42
  • Have you ever needed to implement user-specific shared preferences? For example, an enterprise application for which one device might be used by multiple individuals? I'm assuming in that case you'd need to use Context.getSharedPreferences(name, Context.MODE_PRIVATE); – Justin Pollard Jul 17 '14 at 01:19
  • If the app is running on Android 4.2+ tablets, probably each user should get their own device account, in which case your app would have different internal storage for each user. But, if you really do need multiple users for a phone, then yes, having separate `SharedPreferences` for each is a fine solution. – CommonsWare Jul 17 '14 at 10:36

1 Answers1

2

The @Preference injection uses the PreferenceManager.getDefaultSharedPreferences() method (as CommonsWare suggested) to look up the SharedPreferences object. This is a convenience for using the default preferences directly. Your example would basically generate the following injection:

delegate.favColor = activity.getDefaultSharedPreferences()
                        .getString("favorite_color", "green");

If you like, you can set up Transfuse to inject a specific SharedPreferences object via a Provider or @Provides method and qualifier:

@TransfuseModule
class Module{
    @Provides @Named("the_shared_prefs")
    public SharedPreferences build(Activity activity){
        return activity.getSharedPreferences("the_shared_prefs", Context.MODE_PRIVATE)
    }
}

Which you could then inject into your activity like so:

@Activity
public class MainActivity{
    public static final String PREF_NAME = "pref_name";

    @Inject @Named("the_shared_prefs")
    SharedPreferences theSharedPreferences;

    @Inject @View(R.id.preference)
    EditText mPreferenceEditText;

    @RegisterListener(R.id.button_2)
    android.view.View.OnClickListener mSavePrefListener = new android.view.View.OnClickListener() {
        @Override
        public void onClick(android.view.View v) {
            String val = mPreferenceEditText.getText().toString();
            theSharedPreferences
                .edit()
                .putString(PREF_NAME, val)
                .apply();
        }
    };
}

We may want to expand the @Preference injection to allow you to specify a non-default shared preferences. Would this help?

John Ericksen
  • 10,995
  • 4
  • 45
  • 75
  • Hi John, thanks for your response! At my last company we had the need to distinguish SharedPreferences by the currently signed in user, so I can certainly see expanding @Preference to allow non-default preferences to be valuable in that case. – Justin Pollard Jul 22 '14 at 07:40
  • Hi John, I tried tried what you're doing above, but Transfuse ran into an injection error. I even experimented with copying your code above verbatim, but still got the same error: `org.androidtransfuse.TransfuseAnalysisException: Unable to find injection node for annotated type: android.content.SharedPreferences@javax.inject.Named(value=the_shared_prefs)` – Arjun Menon Jul 24 '16 at 20:32
  • @ArjunG.Menon, did you add the `@Provides` in the module? – John Ericksen Jul 26 '16 at 01:04