是否有针对Android的枚举字符串资源查找模式?

Is there an Enum string resource lookup pattern for Android?

我有一个枚举,我需要将值显示为本地化字符串。 我目前的做法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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());
    }
}

有没有更简单的方法来做到这一点? 如果我能以某种方式根据枚举值名称(即'VALUE1')查找资源,我会喜欢它。

1
2
3
4
5
6
7
8
<?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>

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

编辑:为了将来参考,这是最适合我的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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());
    }
}


您当然可以使用Resources.getIdentifier()按名称查找资源。例如,使用您发布的字符串资源作为示例,您可以通过以下活动执行此操作:

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

从View中,您必须将最后一个参数更改为getContext().getPackageName()


我认为你所尝试的是好的,除了你不需要每次想要翻译枚举时都将资源参数传递给枚举。

使用该链接子类化Application Class,然后按照这种方法。

改善方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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将始终为您提供已翻译的枚举值,但请注意,这可能不是您想要的,例如,您可能有这样的原始查询:

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

这可能会破坏您的应用程序,如果您将枚举值存储为数据库中的VALUE1,VALUE2 ...,那么请记住在不想使用MyEnum的翻译值时使用此MyEnum.VALUEx.name()

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


使用静态应用程序总是不好的做法,因为它不仅打破了Instant Run,而且还违背了编程的解耦原则,从而使模块化难以实现。更不用说Android实际上在单个进程中支持多个应用程序。

出于这个原因,我建议为运行时创建的枚举定义一个内部类,只要可以更改语言环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
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数组,以表示原始枚举的本地化版本。

1
2
3
Example.A.new Entry(context);

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

如果你是你的应用程序类的子类,你可以将它作为单例(参见:http://androidcookbook.com/Recipe.seam?recipeId = 1218)一旦你得到你的
单例实例,您可以在toLocalizedString()中使用它来获取资源对象
并摆脱参数:

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

瞧 - 现在你看起来很干净。


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


首先创建新类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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中添加对应用程序类的引用:

1
 

接下来创建你的枚举。性别的示例枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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);
}}

现在您可以使用请求的查找模式:

1
2
3
4
5
6
7
8
9
// 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);

特别感谢AhmetYüksektepe