Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I strictly avoid using enums on Android?

I used to define a set of related constants like Bundle keys together in an interface like below:

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

This provides me a nicer way to group related constants together and used them by making a static import (not implements). I know Android framework also uses the constants in same way like Toast.LENTH_LONG, View.GONE.

However, I often feel that the Java Enums provide much better and powerful way to represent the constant.

But is there a performence issue in using enums on Android?

With a bit of research I ended up in confusion. From this question "Avoid Enums Where You Only Need Ints” removed from Android's performance tips? it's clear that Google has removed "Avoid enums" from its performance tips, but from it's official training docs Be aware of memory overhead section it clearly says: "Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android." Is this still holds good? (say in Java versions after 1.6)

One more issue that I observed is to send enums across intents using Bundle I should send them by serializing (i.e putSerializable(), that I think an expensive operation compared to primitive putString() method, eventhough enums provides it for free).

Can someone please clarify which one is the best way to represent the same in Android? Should I strictly avoid using enums on Android?

like image 688
nvinayshetty Avatar asked Mar 21 '15 14:03

nvinayshetty


People also ask

Should I avoid enum?

Many people consider Enums as a code smell and an anti-pattern in OOPs. Certain books have also cited enums as a code smell, such as the following. In most cases, enums smell because it's frequently abused, but that doesn't mean that you have to avoid them. Enums can be a powerful tool in your arsenal if used properly.

Should you use enums?

Enums are lists of constants. When you need a predefined list of values which do represent some kind of numeric or textual data, you should use an enum. You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values.

What is the point of using enums?

Enums are used when we know all possible values at compile-time, such as choices on a menu, rounding modes, command-line flags, etc. It is not necessary that the set of constants in an enum type stay fixed for all time. In Java (from 1.5), enums are represented using enum data type.

Why are enums safe?

The enums are type-safe means that an enum has its own namespace, we can't assign any other value other than specified in enum constants. Typesafe enums are introduced in Java 1.5 Version. Additionally, an enum is a reference type, which means that it behaves more like a class or an interface.


2 Answers

Use enum when you need its features. Don't avoid it strictly.

Java enum is more powerful, but if you don't need its features, use constants, they occupy less space and they can be primitive itself.

When to use enum:

  • type checking - you can accept only listed values, and they are not continuous (see below what I call continuous here)
  • method overloading - every enum constant has its own implementation of a method

    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); } 
  • more data - your one constant contains more than one information that cannot be put in one variable

  • complicated data - your constant need methods to operate on the data

When not to use enum:

  • you can accept all values of one type, and your constants contain only these most used
  • you can accept continuous data

    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);         }          ...     } } 
  • for names (like in your example)
  • for everything else that really doesn't need an enum

Enums occupy more space

  • a single reference to an enum constant occupies 4 bytes
  • every enum constant occupies space that is a sum of its fields' sizes aligned to 8 bytes + overhead of the object
  • the enum class itself occupies some space

Constants occupy less space

  • a constant doesn't have a reference so it's a pure data (even if it's a reference, then enum instance would be a reference to another reference)
  • constants may be added to an existing class - it's not necessary to add another class
  • constants may be inlined; it brings extended compile-time features (such as null checking, finding dead code etc.)
like image 75
Kamil Jarosz Avatar answered Oct 12 '22 17:10

Kamil Jarosz


If the enums simply have values, you should try to use IntDef/StringDef , as shown here:

https://developer.android.com/studio/write/annotations.html#enum-annotations

Example: instead of :

enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS}  

you use:

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

and in the function that has it as a parameter/returned value , use:

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

In case the enum is complex, use an enum. It's not that bad.

To compare enums vs constant values, you should read here:

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

Their example is of an enum with 2 values. It takes 1112 bytes in dex file compared to 128 bytes when constant integers are used . Makes sense, as enums are real classes, as opposed to how it works on C/C++ .

like image 38
android developer Avatar answered Oct 12 '22 17:10

android developer