Reputation: 16831
I wish to add the following attribute to a custom view I'm building in Android:
<attr name="sourceType" format="enum">
<enum name="generic" value="???" />
<enum name="dash" value="???" />
<enum name="smooth_streaming" value="???" />
<enum name="hls" value="???" />
</attr>
Internally in my code I would like to use an enum to represent the various source types:
public enum SourceType {
Generic, DASH, SmoothStreaming, HLS;
}
However in my custom view I'm not sure how to convert the attribute value to an enum:
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);
}
I've considered doing something like the following:
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())
);
}
However this feels like the wrong solution:
.fromtInt
and .getValue
to instantiate a new SourceTypeIs there a better solution?
Upvotes: 0
Views: 570
Reputation: 755
To fix your issue that "It requires updating the switch statement if I add new values", you can use the following
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();
}
}
Upvotes: 1
Reputation: 311
Enums have a method values()
that returns an array of that enum's type, with each enum value present in the array. You can define a static array of that enum type as a member of the enum.:
public enum SourceType {
Generic, DASH, SmoothStreaming, HLS;
static final SourceType values[] = SourceType.values();
}
You can then instantiate enum objects like this:
SourceType s = SourceType.values[someInt];
You could of course do this by simply indexing into the array returned by SourceType.values(), but that's less efficient because it creates an array for every call. I believe this solves all three of your problems: You don't have to use any additional methods to instantiate a SourceType; You don't need to manually update the array when adding new values; and you aren't arbitrarily assigning integer values to the enum options.
Upvotes: 1