web-dev-qa-db-fra.com

Existe-t-il un modèle de recherche de ressources de chaîne Enum pour Android?

J'ai une énumération où j'ai besoin d'afficher les valeurs sous forme de chaînes localisées. Mon approche actuelle a été la suivante:

public enum MyEnum {
    VALUE1(R.string.VALUE1),
    VALUE2(R.string.VALUE2),
    .
    .
    VALUE10(R.string.VALUE10);

    private int mResId = -1;

    private MuEnum(int resId) {
        mResId = resId;
    }

    public String toLocalizedString(Resources r) {
        if (-1 != mResId) return (r.getString(mResId));
        return (this.toString());
    }
}

Y at-il un moyen plus facile de faire cela? J'adorerais si je pouvais en quelque sorte rechercher la ressource en fonction du nom de la valeur d'énumération (c'est-à-dire 'VALEUR1').

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="VALUE1"/>My string</string>
    <string name="VALUE2"/>My string 2</string>
    .
    .
    <string name="VALUE10"/>My string 3</string>
</resources>

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EDIT: Juste pour référence future, voici la solution qui a fonctionné le mieux pour moi:

public enum MyEnum {
    VALUE1, 
    VALUE2, 
    . 
    . 
    VALUE10; 

    /**
     * Returns a localized label used to represent this enumeration value.  If no label
     * has been defined, then this defaults to the result of {@link Enum#name()}.  
     * 
     * <p>The name of the string resource for the label must match the name of the enumeration
     * value.  For example, for enum value 'ENUM1' the resource would be defined as 'R.string.ENUM1'.
     * 
     * @param context   the context that the string resource of the label is in.
     * @return      a localized label for the enum value or the result of name()
     */
    public String getLabel(Context context) {
        Resources res = context.getResources();
        int resId = res.getIdentifier(this.name(), "string", context.getPackageName());
        if (0 != resId) {
            return (res.getString(resId));
        }
        return (name());
    }
}
33
jsmith

Vous pouvez certainement rechercher une ressource par son nom en utilisant Resources.getIdentifier(). Par exemple, avec les ressources de chaîne que vous avez publiées à titre d'exemple, vous pouvez le faire à partir d'une activité:

Resources res = getResources();
MyEnum e = MyEnum.VALUE1;
String localized = res.getString(res.getIdentifier(e.name(), "string", getPackageName()));

Dans une vue, il vous faudrait changer le dernier argument en getContext().getPackageName()

20
Ted Hopp

Je pense que ce que vous avez essayé est bon, sauf que vous n'avez pas besoin de passer l'argument de ressources à l'énum chaque fois que vous voulez traduire l'énum. 


Utilisez le link pour sous-classer la classe d'application, puis suivez cette approche.

Meilleure solution

import Android.app.Application;

public enum MyEnum {

    VALUE1(R.string.VALUE1),
    VALUE2(R.string.VALUE2),
    .
    .
    VALUE10(R.string.VALUE10);

    private int resourceId;

    private MyEnum(int id)  {
        resourceId = id;
    }


    @Override
    public String toString() {

        return MyApplication.getApplicationContext().getString(resourceId);

    }

}

Ensuite, appeler MyEnum.VALUEx vous donnera toujours la valeur enum traduite , mais attention, il se peut que ce ne soit pas toujours ce que vous souhaitiez _ par exemple, vous pourriez avoir une requête brute comme celle-ci:

select * from Customer where userStatus = MyEnum.VALUEx.toString();

Cela pourrait endommager votre application si vous stockez les valeurs enum sous la forme VALUE1, VALUE2 ... en db, pensez donc à utiliser cette MyEnum.VALUEx.name() lorsque vous ne souhaitez pas utiliser la valeur traduite de votre MyEnum.

select * from Customer where userStatus = MyEnum.VALUEx.name();
6
dsharew

Utiliser une application statique est toujours une mauvaise pratique, car non seulement elle casse Instant Run, mais elle va également à l'encontre du principe de découplage de la programmation, ce qui rend donc la modularisation difficile à mettre en œuvre. De plus, Android prend en charge plusieurs applications en un seul processus.

Pour cette raison, je suggère de définir une classe interne pour que l'énumération soit créée au moment de l'exécution, chaque fois que les paramètres régionaux peuvent être modifiés.

enum Example {
    A(R.string.label_a),
    B(R.string.label_b);

    Example(@StringRes int label) { mLabel = label; }
    private @StringRes int mLabel;

    class Entry {
        private Context mContext;
        Entry(final Context context) { mContext = context; }
        @Override public String toString() { return mContext.getString(mLabel); }
    }
}

Ensuite, créez l'instance Example.Entry ou le tableau Example.Entry pour représenter la version localisée de l'énumération d'origine.

Example.A.new Entry(context);

Arrays.stream(Example.values()).map(item -> item.new Entry(context)).toArray(Example.Entry[]::new)
2
Oasis Feng

Si vous sous-classez votre classe d'application, vous pouvez l'avoir comme singleton (voir: http: //androidcookbook.com/Recipe.seam? RecipeId = 1218). Une fois que vous avez obtenu votre instance de singleton , Vous pouvez l'utiliser dans toLocalizedString () pour obtenir un objet ressource et se débarrasser du paramètre:

 public String getString() {
    return YourApp.getInstance().getResources().getString(resId);
}

voila - maintenant vous avez une interface propre. 

1

Créez d'abord une nouvelle classe: 

import Android.app.Application;

public class MyApplication extends Application {

    private static MyApplication singleton;

    public static MyApplication getInstance(){
        return singleton;
    }
    @Override
    public void onCreate() {

        super.onCreate();
        singleton = this;
    }
}

Ajoutez maintenant la référence à votre classe d'application dans AndroidManifest.xml:

<application ... Android:name="com.yourPackageName.application.MyApplication  ">

Ensuite, créez votre enum. Exemple enum pour le genre:

public enum Gender {
MALE(0, R.string.male),
FEMALE(1, R.string.female);

private Integer resourceId;
private Integer index;

private static final Map<Integer, Gender> lookupIndex = new HashMap<Integer, Gender>();
private static final Map<Integer, Gender> lookupResourceId = new HashMap<Integer, Gender>();
private static final Map<String, Gender> lookupTranslation = new HashMap<String, Gender>();

static {
    for (Gender g : values()) {
        lookupIndex.put(g.getIndex(), g);
        lookupResourceId.put(g.getResourceId(), g);
        lookupTranslation.put(g.toString(), g);
    }
}

private Gender(Integer index, Integer displayText) {
    this.resourceId = displayText;
    this.index = index;
}

public Integer getIndex() {
    return this.index;
}

public Integer getResourceId() {
    return this.resourceId;
}

public static Gender findByIndex(Integer index) {
    return lookupIndex.get(index);
}

public static Gender findByResourceId(Integer id) {
    return lookupResourceId.get(id);
}

public static Gender findByTranslationText(String text) {
    return lookupTranslation.get(text);
}

@Override
public String toString() {
    return MyApplication.getInstance().getResources().getString(this.resourceId);
}}

Vous pouvez maintenant utiliser le modèle de recherche demandé:

// by index
Gender male = Gender.findByIndex(0);

// by translation
String femaleTranslated = context.getResources().getString(R.string.female);
Gender gender = Gender.findByTranslationText(femaleTranslated);

// by id
Gender gender = Gender.findByResourceId(R.string.female);

Un merci spécial à Ahmet Yüksektepe

0
lidox