Passing enums through aidl interfaces
As enums aren't primitive types, what's th开发者_如何学Goe most effective way to pass an enum through an aidl interface in Android? Is there a way to convert the enum to an ordinal first?
I simply use
String enumString = myEnum.name()
(with MyEnum as enum and myEnum as value) to get the String representation and then
MyEnum myEnum = MyEnum.valueOf(enumString)
to reconstruct the enum from the String representation.
Using Ordinals may be a wee bit faster but if I may add Enums later, this is more likely to break old code.
//Edit: As I don't like to have String as return type, I now implemented Parcellable like mentioned here: Passing enum or object through an intent (the best solution)
import android.os.Parcel; import android.os.Parcelable;
enum InitResponse implements Parcelable {
// Everything is fine.
SUCCESS,
// Something else
FOO;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(name());
}
public static final Creator<InitResponse> CREATOR = new Creator<InitResponse>() {
@Override
public InitResponse createFromParcel(final Parcel source) {
return InitResponse.valueOf(source.readString());
}
@Override
public InitResponse[] newArray(final int size) {
return new InitResponse[size];
}
};
}
Non primitive types, other than
String
, require a directional indicator. Directional indicators includein
,out
andinout
.
Take a look at the official documentation for that: http://developer.android.com/guide/developing/tools/aidl.html#aidlsyntax
Also, you can consider passing the String or ordinal representation of the enum and translate it back when needed. This is taken from the Effective Java 2nd edition:
// Implementing a fromString method on an enum type
private static final Map<String, Operation> stringToEnum = new HashMap<String, Operation>();
static { // Initialize map from constant name to enum constant
for (Operation op : values())
stringToEnum.put(op.toString(), op);
} // Returns Operation for string, or null if string is invalid
public static Operation fromString(String symbol) {
return stringToEnum.get(symbol);
}
In the case above, Operation
is an enum
.
To get the ordinal of an enum consider this example:
public enum Badges{
GOLD, SILVER, BRONZE;
}
// somewhere else:
int ordinal = Badges.SILVER.ordinal();// this should be 1
Yes, you can pass enums through AIDL, but you do have to implement Parcelable on the enum type.
1: A Parcelable implementation.
public enum RepeatMode implements Parcelable {
NoRepeat,
RepeatAll,
RepeatTrack,
;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(toInteger());
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<RepeatMode> CREATOR = new Creator<RepeatMode>() {
@Override
public RepeatMode createFromParcel(Parcel in) {
return RepeatMode.fromInteger(in.readInt());
}
@Override
public RepeatMode[] newArray(int size) {
return new RepeatMode[size];
}
};
public int toInteger() { return this.ordinal(); }
public static RepeatMode fromInteger(int value)
{
return values()[value];
}
}
An import:
RepeatMode.aidl: package com.cyberdyne.media;
parcelable RepeatMode;
And remember to mark enum arguments as in arguments.
Kind of obvious when you think about it. But I'm betting Google doesn't use a whole lot of enums in IBinder interfaces. I do it though. (Thank you Android studio for providing "Implement Parcelable", which doesn't work entirely for enums, but makes things relatively easy).
Discursus on Android enums:
Best practice recommendations against enums in Android were withdrawn many moons ago. You're trading about 200 bytes of executable for horrible horrible code. Phones have come a long way since Android 1.0. It's a no-brainer. Use enums. (Or use the insane Kotlin-driven attribute system that Google uses. Good luck with that.)
Official Java Lore dating back to the Original Java language spec discourages the use of naked ordinal(). The reasoning: maintainers in the deep future may unwittingly re-order the ordinals and break stuff. Frankly, I think that's pompous Java bogosity. I struggled with this for a long time, and after much soul-searching, I caved in.
public enum Badges {
GOLD,SILVER, BRONZE; // Must match @array/badge_states
public int toInteger() { return this.ordinal(); }
public static Badges fromInteger(int value) { return values()[value]);
}
If nothing else, it marks the class as one that probably persists integers. And a comment never hurts, and it makes the receiving end of marshalled enums a bit prettier (and just a tiny bit safer).
精彩评论