我过去常常在如下界面中定义一组相关的常量,如Bundle
个键:
public interface From{
String LOGIN_SCREEN = "LoginSCreen";
String NOTIFICATION = "Notification";
String WIDGET = "widget";
}
这为我提供了一种更好的方法来将相关常量组合在一起,并通过进行静态导入(而不是实现)来使用它们。我知道Android
框架也以Toast.LENTH_LONG
,View.GONE
的相同方式使用常量。
但是,我经常觉得Java Enums
提供了更好,更强大的方法来表示常量。
但在enums
上使用Android
是否存在性能问题?
通过一些研究,我最终感到困惑。从这个问题
"Avoid Enums Where You Only Need Ints” removed from Android's performance tips?很明显,Google
已从其效果提示中删除“避免枚举”,但从其官方培训文档Be aware of memory overhead部分清楚地说明了: “枚举通常需要的内存是静态常量的两倍以上。你应该严格避免在Android上使用枚举。”这仍然很好吗? (比如在1.6之后的Java
版本中)
我观察到的另一个问题是使用enums
在intents
之间发送Bundle
我应该通过序列化发送它们(即putSerializable()
,我认为比较昂贵的操作对于原始putString()
方法,尽管enums
免费提供它。
有人可以澄清哪一个是Android
代表同一个人的最佳方式吗?我应该严格避免在enums
上使用Android
吗?
答案 0 :(得分:102)
在需要其功能时使用enum
。 请不要严格 。
Java枚举更强大,但如果你不需要它的功能,使用常量,它们占用的空间更少,而且它们本身就可以是原始的。
方法重载 - 每个枚举常量都有自己的方法实现
public enum UnitConverter{
METERS{
@Override
public double toMiles(final double meters){
return meters * 0.00062137D;
}
@Override
public double toMeters(final double meters){
return meters;
}
},
MILES{
@Override
public double toMiles(final double miles){
return miles;
}
@Override
public double toMeters(final double miles){
return miles / 0.00062137D;
}
};
public abstract double toMiles(double unit);
public abstract double toMeters(double unit);
}
更多数据 - 您的一个常量包含多个无法放入一个变量的信息
您可以接受连续数据
public class Month{
public static final int JANUARY = 1;
public static final int FEBRUARY = 2;
public static final int MARCH = 3;
...
public static String getName(final int month){
if(month <= 0 || month > 12){
throw new IllegalArgumentException("Invalid month number: " + month);
}
...
}
}
答案 1 :(得分:56)
如果枚举只有值,你应该尝试使用IntDef / StringDef,如下所示:
http://tools.android.com/tech-docs/support-annotations
示例:而不是:
enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}
你使用:
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
并在将其作为参数/返回值的函数中,使用:
@NavigationMode
public abstract int getNavigationMode();
public abstract void setNavigationMode(@NavigationMode int mode);
如果枚举很复杂,请使用枚举。这不是那么糟糕。
要比较枚举与常量值,请阅读:
http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1
他们的例子是一个包含2个值的枚举。在dex文件中需要1112个字节,而使用常量整数时需要128个字节。有道理,因为枚举是真正的类,而不是它在C / C ++上的工作方式。
答案 2 :(得分:11)
我应该严格避免在Android上使用枚举吗?
没有。 &#34; 严格&#34;意味着他们是如此糟糕,他们根本不应该被使用。可能在极端情况下会出现性能问题,例如许多(数千或数百万)带枚举的操作(在ui线程上连续)。更常见的是在后台线程中严格发生的网络I / O操作。 枚举的最常见用法可能是某种类型的检查 - 对象是这个还是 这是如此之快,以至于你无法注意到枚举的单一比较与整数比较之间的差异。
有人可以澄清哪一种是在Android中表示相同的最佳方式吗?
这没有一般的经验法则。使用适用于您的任何内容并帮助您准备好应用程序。稍后进行优化 - 在您发现存在导致应用程序某些方面变慢的瓶颈之后。
答案 3 :(得分:10)
除了之前的答案之外,我想补充一点,如果您使用Proguard(并且您一定要这样做以减小尺寸并模糊代码),那么您的Enums
将自动转换为@IntDef
}只要有可能:
https://www.guardsquare.com/en/proguard/manual/optimizations
<强>类/拆箱/枚举强>
尽可能将枚举类型简化为整数常量。
因此,如果你有一些离散值,某些方法应该只允许这个值而不是同一类型的其他值,那么我会使用Enum
,因为Proguard将使这个手册优化代码我
here is关于使用杰克沃顿的点子的好帖子,请看一下。
作为一名图书馆开发人员,我认识到应该完成的这些小优化,因为我们希望对消费应用的大小,内存和性能产生尽可能小的影响。但重要的是要认识到在适当的情况下将公共API与整数值放在一起是完全正确的。知道差异以做出明智的决定是重要的
答案 4 :(得分:7)
使用Android P,谷歌在使用枚举时没有任何限制/异议
在建议谨慎之前,文档已经发生了变化,但现在还没有提及。 https://developer.android.com/reference/java/lang/Enum
答案 5 :(得分:3)
两个事实。
1,Enum是JAVA中最强大的功能之一。
2,Android手机通常有很多内存。
所以我的答案是否定的。我将在Android中使用Enum。
答案 6 :(得分:2)
我想补充一点,当您声明List&lt;&gt;时,您无法使用@Annotations。或地图&lt;&gt;其中一个键或值是您的一个注释接口。 您收到错误&#34;此处不允许使用注释&#34;。
enum Values { One, Two, Three }
Map<String, Values> myMap; // This works
// ... but ...
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ONE, TWO, THREE})
public @interface Values {}
Map<String, @Values Integer> myMap; // *** ERROR ***
因此,当您需要将其打包到列表/映射中时,请使用枚举,因为它们可以添加,但@annotated int / string groups不能。