在Android中将枚举用于自定义视图属性

时间:2019-05-10 19:06:51

标签: java android enums

问题

我希望将以下属性添加到我在Android中构建的自定义视图中:

        <attr name="sourceType" format="enum">
            <enum name="generic" value="???" />
            <enum name="dash" value="???" />
            <enum name="smooth_streaming" value="???" />
            <enum name="hls" value="???" />
        </attr>

在我的代码内部,我想使用一个枚举来表示各种源类型:

public enum SourceType {
    Generic, DASH, SmoothStreaming, HLS;
}

但是在我的自定义视图中,我不确定如何将属性值转换为枚举:

    public BFPlayer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.BFPlayer);

        // Clearly wrong:
        //    1. SourceType.Generic cannot be cast to int
        //    2. int cannot be cast to SourceType
        SourceType sourceType = attributes.getInt(R.styleable.BFPlayer_sourceType, SourceType.Generic);
    }

我尝试过的

我已经考虑做以下事情:

attrs.xml

        <attr name="sourceType" format="enum">
            <enum name="generic" value="1" />
            <enum name="dash" value="2" />
            <enum name="smooth_streaming" value="3" />
            <enum name="hls" value="4" />
        </attr>

SourceType.java

public enum SourceType {
    Generic (1), DASH (2), SmoothStreaming (3), HLS (4);

    private int value;

    private SourceType(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public static SourceType fromInt(int value) {
        switch (value) {
            case 1: return Generic;
            case 2: return DASH;
            case 3: return SmoothStremaing;
            case 4: return HLS;
            default: throw new Error("Invalid SourceType");
        }
    }
}

BFPlayer.java

    public BFPlayer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.BFPlayer);

        // Clearly wrong:
        //    1. SourceType.Generic cannot be cast to int
        //    2. int cannot be cast to SourceType
        SourceType sourceType = SourceType.fromInt(
            attributes.getInt(R.styleable.BFPlayer_sourceType, SourceType.Generic.getValue())
        );
    }

但是,这感觉像是错误的解决方案:

  • 必须使用.fromtInt .getValue来实例化新的SourceType
  • 如果添加新值,则需要更新switch语句
  • 它为每个选项任意分配整数值

有更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

枚举具有方法values(),该方法返回该枚举类型的数组,每个枚举值都存在于该数组中。您可以将该枚举类型的静态数组定义为枚举的成员。

public enum SourceType {
    Generic, DASH, SmoothStreaming, HLS;

    static final SourceType values[] = SourceType.values();
}

然后可以实例化枚举对象,如下所示:

SourceType s = SourceType.values[someInt];

您当然可以通过简单地索引到SourceType.values()返回的数组来做到这一点,但这效率较低,因为它会为每个调用创建一个数组。我相信这可以解决您所有的三个问题:您不必使用任何其他方法来实例化SourceType;添加新值时,您无需手动更新数组。并且您不会随意将整数值分配给枚举选项。

答案 1 :(得分:1)

要解决您的问题“如果添加新值,则需要更新switch语句”,您可以使用以下

public enum SourceType {
    // ...

    private static final List<SourceType> SOURCE_TYPES_ = Arrays.asList(SourceType.values());

    public static Optional<SourceType> find(int value) {
        return SOURCE_TYPES_ 
                        .stream()
                        .filter(type -> value == type.getValue())
                        .findFirst();
    }
}