¿Debo evitar estrictamente el uso de enums en Android?

Solía ​​definir un conjunto de constantes relacionadas como las claves de Bundle en una interfaz como la siguiente:

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

Esto me proporciona una mejor manera de agrupar las constantes relacionadas y las utilizo haciendo una importación estática (no implementa). Sé que Android marco también utiliza las constantes de la misma manera como Toast.LENTH_LONG , View.GONE .

Sin embargo, a menudo siento que los Java Enums una manera mucho mejor y poderosa de representar la constante.

¿Pero hay un problema de rendimiento en el uso de enums en Android ?

Con un poco de investigación terminé en confusión. De esta pregunta "Evite Enums donde sólo necesita Ints" eliminado de las sugerencias de rendimiento de Android es claro que Google ha eliminado "Evitar enums" de sus consejos de rendimiento, pero de su formación oficial docs Tenga en cuenta la sección de memoria de arriba claramente dice: Los enums requieren a menudo más del doble de memoria que las constantes estáticas. Usted debe evitar estrictamente el uso de enums en Android. " ¿Esto todavía está bien? (Digamos en las versiones de Java después de 1.6)

Un problema más que he observado es enviar enums través de intents usando Bundle I debería enviarlos por serialización (es decir, putSerializable() , que creo que una operación costosa en comparación con el método putString() primitivo, a pesar de enums proporciona de forma gratuita).

¿Puede alguien aclarar cuál es la mejor manera de representar lo mismo en Android ? ¿Debo evitar estrictamente el uso de enums en Android ?

Use enum cuando necesite sus características. No lo evites estrictamente .

Java enum es más potente, pero si no necesita sus características, use constantes, ocupan menos espacio y pueden ser primitivas en sí.

Cuándo usar el enum:

  • Tipo de verificación – puede aceptar sólo los valores de la lista, y no son continuos (véase a continuación lo que yo llamo continuo aquí)
  • Sobrecarga de métodos – cada constante de enum tiene su propia implementación de un método

     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); } 
  • Más datos – su constante contiene más de una información que no se puede poner en una variable

  • Datos complicados – su constante necesidad de métodos para operar en los datos

Cuando no usar enum:

  • Puede aceptar todos los valores de un tipo, y sus constantes contienen sólo los más utilizados
  • Puede aceptar datos continuos

     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); } ... } } 
  • Para nombres (como en su ejemplo)
  • Para todo lo demás que realmente no necesita un enum

Enum ocupa más espacio

  • Una sola referencia a una constante del enum ocupa 4 bytes
  • Cada constante del enum ocupa el espacio que es una suma de los tamaños de sus campos alineados a 8 bytes + sobrecarga del objeto
  • La clase enum ocupa un cierto espacio

Constante ocupa menos espacio

  • Una constante no tiene una referencia por lo que es un dato puro (incluso si es una referencia, entonces la instancia enum sería una referencia a otra referencia)
  • Las constantes se pueden agregar a la clase existente – no es necesario agregar otra clase
  • Las constantes pueden estar en línea; Que trae características extendidas de tiempo de compilación (como la comprobación nula, encontrar código muerto, etc)

Si los enums simplemente tienen valores, intente utilizar IntDef / StringDef, como se muestra aquí:

http://tools.android.com/tech-docs/support-annotations

Ejemplo: en lugar de:

 enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS} 

tu usas:

 @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; 

Y en la función que lo tiene como parámetro / valor devuelto, use:

 @NavigationMode public abstract int getNavigationMode(); public abstract void setNavigationMode(@NavigationMode int mode); 

En caso de que el enum sea complejo, use un enum. No está tan mal.

Para comparar enums vs valores constantes, debe leer aquí:

http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1

Su ejemplo es un enum con 2 valores. Toma 1112 bytes en archivo dex comparado con 128 bytes cuando se usan números enteros constantes. Tiene sentido, ya que los enums son clases reales, en contraposición a cómo funciona en C / C ++.

¿Debo evitar estrictamente el uso de enums en Android?

No. " Estrictamente " significa que son tan malos, que no deben ser utilizados en absoluto. Posiblemente un problema de rendimiento podría surgir en una situación extrema como muchos muchos (miles o millones de) operaciones con enums (consecutivos en el hilo ui). Mucho más comunes son las operaciones de E / S de red que deberían suceder estrictamente en un hilo de fondo. El uso más común de enums es probablemente algún tipo de comprobación de tipo: si un objeto es esto o lo que es tan rápido que no será capaz de notar una diferencia entre una sola comparación de enums y una comparación de números enteros.

¿Puede alguien aclarar cuál es la mejor manera de representar lo mismo en Android?

No hay una regla general para esto. Utilice lo que funcione para usted y le ayudará a preparar su aplicación. Optimizar más tarde – después de observar que hay un cuello de botella que ralentiza algunos aspectos de su aplicación.

Además de las respuestas anteriores, añadiría que si está usando Proguard (y definitivamente debería hacerlo para reducir el tamaño y ofuscar su código), entonces sus Enums se convertirán automáticamente en @IntDef donde sea posible:

https://www.guardsquare.com/es/proguard/manual/optimizaciones

Clase / unboxing / enum

Simplifica tipos de enumeración a constantes enteras, siempre que sea posible.

Por lo tanto, si usted tiene algunos valores discretos y algún método debe permitir tomar sólo estos valores y no otros del mismo tipo, entonces yo usaría Enum , porque Proguard hará este trabajo manual de optimización de código para mí.

Y aquí está un buen post sobre el uso de enums de Jake Wharton, eche un vistazo a él.

Como desarrollador de la biblioteca, reconozco estas pequeñas optimizaciones que deberían realizarse ya que queremos tener el menor impacto posible en el tamaño, la memoria y el rendimiento de la aplicación que consumen. Pero es importante darse cuenta de que […] poner un enum en sus valores públicos de API vs. valores enteros donde sea apropiado está perfectamente bien. Saber la diferencia para tomar decisiones informadas es lo importante

Me gusta agregar, que no se puede utilizar @Annotations cuando se declara una lista <> o mapa <> donde la clave o el valor es de una de sus interfaces de anotación. Usted obtiene el error "Anotaciones no están permitidos aquí".

 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 *** 

Así que cuando necesitas empacarlo en una lista / mapa, usa enum, ya que se pueden agregar, pero @annotated int / string groups no puede.

Dos hechos.

1, Enum es una de las funciones más poderosas de JAVA.

2, teléfono Android por lo general tiene un montón de memoria.

Así que mi respuesta es NO. Usaré Enum en Android.

  • ¿Está creando lo siguiente para loop bad para Garbage Collection?
  • ¿Por qué no puedo usar las anotaciones de Anulación en Android?
  • Android NoSuchField error en R.java después de que el proceso es matado
  • ActionBarSherlock - Compartir Contenido icon issue
  • ¿Cómo puedo eliminar caracteres no reconocidos que vuelven de un servicio web?
  • Equivalente de Ruby #map o #collect en Java?
  • Java.util.zip.ZipException: entrada duplicada: cómo superar
  • Validación de Token GCM
  • ¿Qué significa usar un "." Sin un objeto en Android (o java)?
  • Crear notificación de emisión diaria mediante Firebase Cloud Messaging
  • Cosas más extrañas en la resolución de clases de Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.