我应该严格避免在Android上使用枚举吗?

我曾经在一个像下面的界面中一起定义一组相关的常量,比如Bundle键。

 public interface From{ String LOGIN_SCREEN = "LoginSCreen"; String NOTIFICATION = "Notification"; String WIDGET = "widget"; } 

这提供了一个更好的方法来将相关的常量组合在一起,并通过静态导入(而不是实现)来使用它们。 我知道Android框架也使用像Toast.LENTH_LONGView.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组不能。