开发者

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 include in, out and inout.

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];
    }
}
  1. An import:

    RepeatMode.aidl: package com.cyberdyne.media;

    parcelable RepeatMode;

  2. 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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜