通过AIDL接口传递枚举类型

8

由于枚举类型不是原始类型,因此在Android中通过AIDL接口传递枚举的最有效方法是什么?是否有一种将枚举转换为序数的方法?


看看Charlie Collins的评论。那是完全正确的:尽可能避免使用枚举。 - Cristian
@Cristian 需要注意的是,这需要根据实际情况具体分析。枚举是良好的设计方式,Android语言中没有移除枚举的原因亦在此。 - Jeffrey Blattman
没错,伙计。不过我认为他们没有移动它是因为这并不容易。他们在对字节码进行 dexing 之前仍然使用 javac。无论如何……我喜欢枚举,并在它们能使事情变得清晰优雅时使用它们。 - Cristian
1
枚举在应用程序代码中完全没有问题。框架的作者遵循不同的约束条件。(例如,MFC 在其核心类中避免使用虚函数)。特别是对于 Android 平台,早期测试显示枚举比常量消耗更多的内存,因此该框架避免使用它们。你的结果可能会有所不同。实际上,你的结果必定不同,因此要为你的应用程序做正确的事情,而不仅仅是跟随大众。 - Ian Ni-Lewis
1
在深网的某个角落,Google允许我们在Android代码中使用枚举。一个枚举大约需要600字节。自Android 1.0以来,手机已经发展了很长一段时间。放心去做吧。 - Robin Davies
3个回答

9

我只是使用

String enumString = myEnum.name() 

(使用枚举类型 MyEnum 和值 myEnum) 获取字符串表示,然后

MyEnum myEnum = MyEnum.valueOf(enumString) 

重新构建枚举类型需要使用字符串表示。

虽然使用序号可能会更快,但是如果以后需要添加枚举类型,这很可能会破坏旧代码。

//编辑:由于我不喜欢返回类型为字符串,我现在已经按照此处所述实现了Parcellable:通过意图传递枚举或对象(最佳解决方案)

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];
    }
};

}

1
我现在将这种方法与https://dev59.com/j3E85IYBdhLWcg3wUByz中的Parcellable实现相结合,从而得到了上面编辑过的代码。 - domenukk

5
非原始类型,除了String,需要方向指示符。 方向指示符包括 inoutinout。请参阅官方文档:http://developer.android.com/guide/developing/tools/aidl.html#aidlsyntax。此外,您可以考虑传递枚举的字符串或序数表示,并在需要时进行翻译。这是来自Effective Java第2版的建议:
// 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);
}

在上述情况下,Operation 是一个 enum
获取枚举的序数,可以考虑以下示例:
public enum Badges{
    GOLD, SILVER, BRONZE;
}

// somewhere else:
int ordinal = Badges.SILVER.ordinal();// this should be 1

1
如果可以的话,在Android项目中你也应该考虑完全避免使用枚举。http://developer.android.com/guide/practices/design/performance.html#avoid_enums - Charlie Collins
很遗憾,我没有避免使用枚举的选项;这是一个协作项目。我能提取枚举值的序数吗? - Phillip
6
那条建议已经被撤回了。 - Sandeep Datta

4

是的,你可以通过AIDL传递枚举类型,但是你必须在枚举类型上实现Parcelable接口。

1:一个Parcelable实现。

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. 一个导入:

    RepeatMode.aidl: package com.cyberdyne.media;

    可重复的 RepeatMode;

  2. 记得将枚举参数标记为输入参数。

当你想到它时,这种做法似乎很明显。但我敢打赌 Google 在 IBinder 接口中并不常用枚举类型。尽管如此,我仍然这样做。(感谢 Android Studio 提供的“实现 Parcelable”,虽然对于枚举类型并不完全有效,但使事情相对容易)。

关于 Android 枚举的讨论:

多年前,最佳实践建议避免在 Android 中使用枚举类型。你会因为可怕的代码而交换大约 200 字节的可执行文件。自 Android 1.0 以来,手机已经发展了很长时间。毫无疑问,应该使用枚举类型。(或者使用 Google 使用的疯狂的 Kotlin 驱动属性系统。祝你好运。)

官方 Java 知识库追溯到最初的 Java 语言规范,反对使用裸的 ordinal()。原因是:在未来的维护期间,维护人员可能会无意中重新排序 ordinals 并破坏一些东西。坦白地说,我认为这是自命不凡的 Java 糊涂话。我为此苦苦挣扎了很长时间,在经过深思熟虑后,我妥协了。

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]);
}

如果没有其他内容,它标记了该类可能持久保留整数。而注释从来没有坏处,使得枚举的接收端看起来更漂亮(稍微安全一点)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接