我应该严格避免在Android上使用枚举吗?
我曾经在一个像下面的界面中一起定义一组相关的常量,比如Bundle
键。
public interface From{ String LOGIN_SCREEN = "LoginSCreen"; String NOTIFICATION = "Notification"; String WIDGET = "widget"; }
这提供了一个更好的方法来将相关的常量组合在一起,并通过静态导入(而不是实现)来使用它们。 我知道Android
框架也使用像Toast.LENTH_LONG
, View.GONE
一样的View.GONE
。
不过,我经常觉得Java Enums
提供了更好更强大的方式来表示常量。
但是在Android
上使用enums
有没有一个性能问题?
通过一些研究,我最终陷入困惑。 从这个问题“避免在只需要Ints的地方引用”从Android的性能提示中删除了很明显, Google
已经从其性能提示中删除了“避免枚举” ,而是从官方培训文档中删除了内存开销部分。 枚举通常需要比静态常量多两倍的内存。 你应该严格避免在Android上使用枚举(enums)。“这是否仍然有效?(比如1.6版本以后的Java
版本)
我观察到的另外一个问题是使用Bundle
发送各种intents
enums
我应该通过序列化(即putSerializable()
发送它们,相比于原始的putString()
方法,尽pipeenums
提供了免费的操作。
有人可以澄清哪一个是最好的方式来代表相同的Android
? 我应该严格避免在Android
上使用enums
吗?
使用enum
当你需要它的function。 不要严格避免 。
Java的枚举更强大,但如果你不需要它的特性,使用常量,它们占用的空间就更小了,它们本身就可以是原始的。
何时使用枚举:
- types检查 – 你只能接受列出的值,而且不是连续的(见下面我在这里连续调用的)
-
方法重载 – 每个枚举常量都有自己的方法实现
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); }
-
更多的数据 – 你的一个常量包含不能放在一个variables中的多个信息
- 复杂的数据 – 你不断需要的方法来操作数据
何时不使用枚举:
- 你可以接受一个types的所有值,而你的常量只包含这些最常用的值
-
你可以接受连续的数据
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); } ... } }
- 对于名称(如你的例子)
- 对于其他所有不需要枚举的东西
Enum占据更多的空间
- 对枚举常量的单引用占用4个字节
- 每个枚举常量占用的空间是它的字段大小alignment到8个字节+ 对象的开销的 总和
- 枚举类本身占据一些空间
常量占用的空间较less
- 一个常量没有引用,所以它是一个纯数据(即使它是一个引用,那么枚举实例将是对另一个引用的引用)
- 常量可以添加到现有的类 – 没有必要添加另一个类
- 常量可以内联; 它带来了扩展的编译时function(如空检查,查找死代码等)
如果枚举只是有值,则应该尝试使用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 ++上工作。
我应该严格避免在Android上使用枚举吗?
不是,“ 严格 ”意味着他们是如此糟糕,根本不应该使用。 性能问题可能会出现在很多很多 (数千或数百万)带有枚举的操作(在ui线程上是连续的)的极端情况下。 在后台线程中应该严格执行的networkingI / O操作更为常见。 枚举最常见的用法可能是某种types检查 – 无论对象是这样还是那么快,你都不会注意到枚举的比较和整数的比较之间的区别。
有人可以澄清哪一个是最好的方式来代表相同的Android?
对此没有一般的经验法则。 使用任何适合您的工具,并帮助您准备好应用。 稍后进行优化 – 在您注意到之后,存在一个瓶颈,会降低应用的某些方面。
除了以前的答案之外,我还要补充一点,如果你使用的是Proguard(你一定要这样做,以减less大小和混淆你的代码),那么你的Enums
将被自动转换为@IntDef
只要有可能:
https://www.guardsquare.com/en/proguard/manual/optimizations
类/拆箱/枚举
尽可能简化枚举types为整型常量。
因此,如果你有一些离散的值,并且某些方法应该只允许取这个值而不是其他types的值,那么我会使用Enum
,因为Proguard会为我做这个手动优化代码的工作。
这里有一篇关于使用杰克·沃顿的枚举的好post,请看一下。
作为一名图书馆开发人员,我认识到应该完成这些小的优化,因为我们希望尽可能less地影响应用程序的大小,内存和性能。 但是,认识到将public枚举中的枚举与适当的整数值放在一起非常重要。 知道区别做出明智的决定是重要的
两个事实。
1,Enum是JAVA中最强大的function之一。
2,Android手机通常有很多内存。
所以我的答案是否定的。 我将在Android中使用Enum。
我想补充一点,当你声明一个List <>或Map <>键或值是你的一个注解接口的时候,你不能使用@Annotations。 您收到错误“此处不允许注释”。
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整数/string组不能。