Подтвердить что ты не робот

Есть ли шаблон поиска ресурса строки Enum для Android?

У меня есть перечисление, где мне нужно отображать значения как локализованные строки. Мой нынешний подход был следующим:

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());
    }
}

Есть ли более простой способ сделать это? Мне бы это понравилось, если бы я мог каким-то образом найти ресурс на основе имени значения перечисления (i.e "VALUE1" ).

<?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: только для справок в будущем, это решение, которое наилучшим образом подходит для меня:

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());
    }
}
4b9b3361

Ответ 1

Вы можете найти ресурс по имени, используя Resources.getIdentifier(). Например, со строковыми ресурсами, которые вы отправили в качестве примера, вы можете сделать это из действия:

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

В представлении вам нужно будет изменить последний аргумент на getContext().getPackageName()

Ответ 2

Я думаю, что вы пробовали хорошо, за исключением того, что вам не нужно передавать аргумент ресурсов для перечисления каждый раз, когда вы хотите перевести перечисление.


Используйте ссылку для подкласса класса приложения, затем следуйте этому подходу.

Лучшее решение

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);

    }

}

Тогда вызов MyEnum.VALUEx всегда даст вам переведенное значение перечисления, но будьте осторожны, это может быть не то, что вы хотите всегда, например, у вас может быть такой необработанный запрос:

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

Это может сломать ваше приложение, если вы сохраняете значения перечисления как VALUE1, VALUE2... в db, поэтому не забудьте использовать этот MyEnum.VALUEx.name(), когда вы не хотите использовать переведенное значение MyEnum.

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

Ответ 3

Использование статического приложения - это всегда плохая практика, потому что не только он прерывает Instant Run, но и это противоречит принципу развязки программирования, что затрудняет реализацию модуляции. Не говоря уже о том, что Android фактически поддерживает несколько приложений в одном процессе.

По этой причине я бы предложил определить внутренний класс для перечисления, который будет создан во время выполнения, всякий раз, когда локаль может быть изменена.

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); }
    }
}

Затем создайте экземпляр Example.Entry или массив Example.Entry, чтобы представить локализованную версию исходного перечисления.

Example.A.new Entry(context);

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

Ответ 4

Если вы подклассифицируете свой класс приложения, вы можете использовать его как singleton (см. http://androidcookbook.com/Recipe.seam? recipeId = 1218). Когда вы получили свой Singleton, вы можете использовать его в toLocalizedString() для получения объекта ресурса и избавиться от параметра:

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

voila - теперь у вас чистый интерфейс.

Ответ 5

Сначала создайте новый класс:

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;
    }
}

Теперь добавьте ссылку на свой класс приложения в AndroidManifest.xml:

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

Затем создайте свой список. Пример перечисления для пола:

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);
}}

Теперь вы можете использовать запрошенный шаблон поиска:

// 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);

Чрезвычайная благодарность Ahmet Yüksektepe

Ответ 6

enum class MeasurementEnum(var position: Int, @StringRes
                    var userRedableStringRes: Int) {
    False(0, R.string.boolean_false),
    True(1,R.string.boolean_true)
}