Where to store Android preference keys?
Asked Answered
A

7

64

When I create preference activity I define all preferences in xml file. Every preference has a key defined in this xml. But when I access preference I write:

SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean foo_value = appPreferences.getBoolean("foo_key_defined_in_xml", false);

Is there any way to avoid referencing "foo_key_defined_in_xml" in hard-coded way? Maybe there is a possibility to reference it in R style way (not to refer to string)?

Aten answered 18/5, 2010 at 12:18 Comment(0)
A
75

I've found that it's possible to store keys in strings.xml and refer to them from preferences.xml just like all other values android:key="@string/preference_enable".

In code you can refer to key by typing getString(R.string.preference_enable)

You can mark the string to not be translated using a <xliff:g> tag. See Localization Checklist

<string name="preference_enable"><xliff:g id="preference_key">enable</xliff:g></string>
Aten answered 19/5, 2010 at 9:10 Comment(6)
This is the best way because it allows you to change the key in one place and it will propagate to both the settings page and anywhere you reference it in code.Carmichael
I would advise against this because when you support multiple language xml files, the key string might be inadvertantly translated too.Donnadonnamarie
Well, you should save those keys in a different file which only contains static values and no translations.Iffy
wow, i suggest reading the official tutorial, for those who still confuse about this developer.android.com/training/basics/data-storage/…Lyric
@Singgum3b: the link you suggested tells us to reference a regular string ala R.string.my_key. This is problematic because when you send strings.xml file off to be translated, your key will be translated too, resulting in potential errors (from different versions). Using the <xliff:g> is not guaranteed to work either; it does not hide the string from translators nor does it prevent them from making changes. So we're still left with the localization problem. Sigh.Sharp
I would also mark the keys in strings.xml as translatable="false" like <string name="preference_enable" translatable="false">...Chrisom
E
15

You could use a "keys.xml" files in "res/values", but should put something like this, this way you should dont have problem when you are using multiple languages:

    <resources
    xmlns:tools="http://schemas.android.com/tools"
    tools:ignore="MissingTranslation">

    <string name="key1">key1</string>
    <string name="key2">key2</string>
...
</resources>

Then you could reference it like a normal string in xml:

....
android:key="@string/key1"
....

or in your java code for example:

SwitchPreference Pref1= (SwitchPreference) getPreferenceScreen().findPreference(getString(R.string.key1));
Equipage answered 27/3, 2016 at 3:54 Comment(1)
I like it better than the accepted answer because it's cleaner (and actually suggested in the comments to that answer). Alas, the "string/" namespace will still be polluted with both actual strings and preference keys - will have to use a prefix to solve it somewhat nicely.Benzel
F
5

In strings.xml mark the key as untranslatable:

<string name="screw_spacing_key" translatable="false">Screw spacing</string>
<string name="screw_spacing_title">Screw spacing</string>
<string name="screw_spacing_summary">Set screw spacing</string>

Usage:

<EditTextPreference
    android:key="@string/screw_spacing_key"
    android:title="@string/screw_spacing_title"
    android:summary="@string/screw_spacing_summary"/>

See: Configure untranslatable rows

Feuchtwanger answered 25/9, 2018 at 0:23 Comment(2)
I think this is the clearest and most suitable answer. Yes, we still rely on hand-coding translators to honor this request to not translate, but it's documented and easy to understand. Furthermore many automated translation tools recognize this automatically and don't display the untranslatable strings at all. Why am I the first to upvote this, am I missing something?Sharp
On file level the translatable attribute becomee effective for pseudo translation only.<br/> https://androidstudio.googleblog.com/2020/08/android-studio-42-canary-8-available.html (Issue #118332958).Cymogene
T
1

As far as I know there's no better way of referencing preference keys (aside from maybe using a static final String to store the string on the class).

The example given in the SDK docs does the same as what you've given in your example,

Thanasi answered 18/5, 2010 at 12:33 Comment(1)
This is how I like to do it. This way when you create a new key, in the same file you created it in, theres a public static final String reference to it that's readily available to any class that might need to reference it.Affirm
K
1

Try getString(R.string.key_defined_in_xml).

Kagoshima answered 18/5, 2010 at 12:37 Comment(1)
Doesn't work. Values from android:key aren't stored in this class.Testaceous
M
1

What about using a helper class to hide the getString() - instantiate the helper once in each activity or service. For example:

class Pref {

    final String smsEnable_pref;
    final String interval_pref;
    final String sendTo_pref;
    final String customTemplate_pref;
    final String webUrl_pref;

    Pref(Resources res) {       
         smsEnable_pref = res.getString(R.string.smsEnable_pref);
         interval_pref = res.getString(R.string.interval_pref);
         sendTo_pref = res.getString(R.string.sendTo_pref);
         customTemplate_pref = res.getString(R.string.customTemplate_pref);
         webUrl_pref = res.getString(R.string.webUrl_pref);
    }
}
Marketable answered 9/2, 2011 at 10:38 Comment(1)
I'm not sure what ddcruver means by Even if you define a resoure in /res/values/string.xml to hold this key name you can not use that in the android:key="key_name". As Pixel wrote, you can do android:key="@string/preference_key". Maybe I'm missing something.Marketable
F
0

Not sure if this post need another answer, put i end up to it like this:

-Extend all the Preference needed and add this code

   final static private int[] ATTR_INDEX = {android.R.attr.id};
    private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
        if(attrs == null) return;
        AttributeReader attributes = new AttributeReader().setAttrsIndex(ATTR_INDEX).parse(attrs);
        int id = attributes.asResourceID(0);
        setKey(AppContext.getIdentifierName(id));
    }
  • In the xml, don't use the key attribute but android:id="@+id/...
  • And finally to get back the value,

    SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getContext()); String preference_1 = SP.getString(AppContext.getIdentifierName(R.id.pref_key_1), null);

This way, you don't have to create a string file who need to be maintain, just create any id on the fly. But you need to be familiar with extending a view and get read the attr to find what you want (Here the id attribute)

Freshman answered 9/5, 2020 at 6:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.