14

Reading about Android I can see many parts of the framework using int constants for a return value, or configuration value (like in here in the START_REDELIVER_INTENT), instead of an enum, which as far as I know is a better option for many reasons that can be found all around the web, like this.

So this makes me wonder...why Google decided to use so many int's instead of enum's?

Community
  • 1
  • 1
Michel Feinstein
  • 13,416
  • 16
  • 91
  • 173
  • 1
    I guess it is an extension of the question, but is it possible they actually didn't want to worry about the type-safe aspect of enums and wanted a things to be more consistent by using ints for constants? – zgc7009 Jul 28 '14 at 19:59
  • what makes constants more consistent? And when does type-safe becomes a trouble? – Michel Feinstein Jul 28 '14 at 20:01
  • 3
    Simple to save memory, what they are doing is manipulating the bits instead of wasting 8 bits they are only using one bit for each of the constant. – Rod_Algonquin Jul 28 '14 at 20:01
  • Because there is more memory overhead with `enum` than there is with straight `ints` – tyczj Jul 28 '14 at 20:01
  • @zgc7009 Would you mind elaborating on the "worry about the type-safe aspect of enums"? – StoneMan Jul 28 '14 at 20:04
  • 1
    Re-opened, as the proposed duplicate was really asking a different question and did not have answers satisfying the question asked here. – Chris Stratton Jul 28 '14 at 20:05
  • The answer marked as duplicated is marked as out of date as of March 2011.... – Michel Feinstein Jul 28 '14 at 20:06
  • @mFeinstein Correct me if I am wrong, but wouldn't something like Color cause an issue? If your constants were of type Color, but you wanted to use something other than Color to work with colors, wouldn't you run into a type issue? Haven't messed with enums in a while so might be thinking of it completely wrong :P – zgc7009 Jul 28 '14 at 20:07
  • Also the answer marked as duplicate shows that there are VM optimizations and diminish the memory impact of enums, although I didn't dig it deeply to compare the benchmarks – Michel Feinstein Jul 28 '14 at 20:07
  • @zgc7009 I am not a specialist in java, and I am not sure I fully comprehend your example...but as far as I know if you are dealing with enums, only the declared enums could be used, but if you are dealing with constant ints, every single number that an int can hold can be used as a reference, even numbers that represent stuff that the code doest declare or represent, which might trigger problems.....for example, you could mess up and declare the same number for 2 references....or someone could pass a number and try to trigger a bug in your code – Michel Feinstein Jul 28 '14 at 20:11
  • @mFeinstein yea I think I am thinking of this wrong, I haven't messed with Java outside of Android in a while, not trying to confuse people (including myself) so might just let this one be. It just seemed to me that if you used enums you are limited to that enum type when trying to use framework methods, which would limit people in the ways they could use the framework. I thought that was one of the reasons they organized the R file the way that they did, so you could use ints for everything without having to worry about type and collision. – zgc7009 Jul 28 '14 at 20:14
  • well I guess you are limited...thats the point, you can only use enums of the type that is expected, and nothing else....much like a class, you can only use a class of the type of the class variable...a variable of class `Dog` wont hold an instance of a class `House`...same thing happens with enums, you declare them, so you assure only the types declared in that enum are valid – Michel Feinstein Jul 28 '14 at 20:18

3 Answers3

8

pulled straight from the doc's

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

http://developer.android.com/training/articles/memory.html#Overhead

Edit:

also a slide from one of Roman Guy's talks

https://speakerdeck.com/romainguy/android-memories?slide=67

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • 1
    This is not the primary reason – Chris Stratton Jul 28 '14 at 20:08
  • @ChrisStratton no its an over simplification as to why they use and recommend static ints instead of enums – tyczj Jul 28 '14 at 20:10
  • No, it's at most tangential to the question asked. – Chris Stratton Jul 28 '14 at 20:11
  • 3
    @ChrisStratton Question: "why Google decided to use so many int's instead of enum's". Documentation from Google: "Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.". Tell me more about how this is tangential? – Jack Jul 28 '14 at 20:20
  • 5
    @ChrisStratton The question is why a certain groups of developers used a certain technique (which seems a reason to VTC as opinion based imo). He posted the reason that Google said Google did it. That sounds like the absolute answer to me. We should trust your guess as to why they did it more than their documentation? – Gabe Sechan Jul 28 '14 at 20:23
  • 5
    So in other words, the Google devs are obsessed with premature optimization. But we knew that; it's evident in the philosophy of their whole API design. – Brodo Fraggins Jul 28 '14 at 20:27
  • 4
    "You should strictly avoid using enums on Android." Wow, that is outrageously bad advice. – Kevin Krumwiede Jul 30 '14 at 00:17
  • While tygcz's answer is "correct", in the sense that it gives the explanation of why Google coded it this way, I find it unsatisfactory as coding advice, as per Gabe and Brodo [love the handle, BTW]. An enum takes "twice as much memory" - that is, 64 bits as opposed to 32 bits. But how many Services are under Android control? Thousands? So Google has distorted one of its most important API's to save perhaps a K or two of memory? Why not make the return value a short or a byte (cf START_CONTINUATION_MASK)? I would like to hear an extended justification for this. – Robert R Evans Aug 04 '16 at 14:54
6

Operations on int occur many times faster than operations on enum.

Judge for yourself. Each time you create a enum you create as a minimum:

1) Class-loader for it. 
2) You keep this object in memory. 
3) Since enum is static anonymous class - it will always hang in your memory (sometimes even after you close the application.) 

With regard to the Service. In this class, the flags are mainly used for comparisons and return the result to the class above (ContextWrapper). But basically, if you dig into the bowels of Android SDK you will discover for yourself that almost all these flags are used to bynary shift operations.

Even in Java use a binary shift operations in JDK :

/**
 * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY.
 */
private static final int MAXIMUM_CAPACITY = 1 << 30;

Also you can look to Window class in Android SDK

/**
 * Set the container for this window.  If not set, the DecorWindow
 * operates as a top-level window; otherwise, it negotiates with the
 * container to display itself appropriately.
 *
 * @param container The desired containing Window.
 */
public void setContainer(Window container) {
    mContainer = container;
    if (container != null) {
        // Embedded screens never have a title.
        mFeatures |= 1<<FEATURE_NO_TITLE;
        mLocalFeatures |= 1<<FEATURE_NO_TITLE;
        container.mHasChildren = true;
    }
}

/** The default features enabled */
@SuppressWarnings({"PointlessBitwiseExpression"})
protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |
        (1 << FEATURE_CONTEXT_MENU);

So reasons is two(at least):

  • Less memory consumption.

  • Working faster due bitwise operations.

Sergey Shustikov
  • 15,377
  • 12
  • 67
  • 119
  • 3
    This is an absurdly overcomplicated way of saying "because power-of-two integer constants combine cleanly" – Chris Stratton Jul 28 '14 at 20:07
  • @ChrisStratton Build expressions from your understanding of bits/binary. This means embracing hex values and bit-shifted constants instead of their decimal equivalents. For example, a mask to extract the sign bit from a 32-bit value can be cleanly expressed as 1 << 31 or 0x80000000 and both are quite readable. The mask also happens to be unsigned decimal value 2147483648, but who can tell? Don't make yourself have to translate between binary and decimal to follow along – Sergey Shustikov Jul 28 '14 at 20:10
  • I didn't say you were wrong, I said your explanation was absurdly overcomplicated - to the point that hardly anyone who might benefit would bother to read it. – Chris Stratton Jul 28 '14 at 20:12
  • Wow is it a crash course on bitwise operations? haha....I have to agree with @ChrisStratton a little, that's a bit (pun intended) overwhelming, a simple reference to an article will do..but thanks for the documentations anyways :) – Michel Feinstein Jul 28 '14 at 20:14
  • By saying that enums are anonymous classes, and will be hold in memory for a long time, are you implying they are a great source of memory leaks? – Michel Feinstein Jul 28 '14 at 20:36
  • If you adress the first time to any Enum constant you load Enum-class into your memory and he will living even after close the app. It will be destroyed after your process will be down(not ever). So it's undestroyable object in your memory. Keep in mind. – Sergey Shustikov Jul 28 '14 at 20:41
  • 2
    Memory consumption is a ridiculous reason not to use enums. The amount of memory they use is negligible compared to the hundreds or even thousands of other classes loaded by the JVM. And they are no more undestroyable than any other class. If the OS needs the memory, it will kill the process. – Kevin Krumwiede Jul 30 '14 at 00:12
  • 2
    And you *can* effectively do bitwise combination on enums: http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html – Kevin Krumwiede Jul 30 '14 at 00:20
  • @KevinKrumwiede Your guess is as unconvincing. Give it more explanation. – Sergey Shustikov Jul 30 '14 at 08:00
  • 5
    The `enum` keyword is basically syntactic sugar for defining an ordinary class that extends `java.lang.Enum`. Enums have the same persistence in the permgen as any other static class. Do they use more memory than int constants? Of course they do. But we're talking about a few kilobytes. Sacrificing type safety, clarity of purpose, and maintainability for the sake of that kind of micro-optimization is widely regarded as bad practice. – Kevin Krumwiede Jul 30 '14 at 19:28
0

As some of the other answers correctly state, the reason for this is because enums use more memory than int.

To give context to that decision, you have to remember that the first Android device had 192mb of RAM.

As explained in the closest thing to an official statement from Google, enums aren't just 2x the size of an int, but when the dex is loaded into RAM it could be 13x the size. Therefore the framework team is very careful to prematurely optimize their code in that regard. If there were devices with 4gb of RAM when Android was being developed, maybe this would be different, but we'll never know.

The recommendation for non framework development is to make a judgment for your own use cases. It never hurts to remember that Proguard will usually convert your enums into ints anyways.

Eliezer
  • 7,209
  • 12
  • 56
  • 103