IntDef and StringDef in Android

We often use View’s visibility in our apps to show and hide them. We use void setVisibility(int visibility) method for that purpose. But have you ever thought that why this method always takes VISIBLE, INVISIBLE and GONE rather than any int value like 0 or 1 etc.? Although method’s parameter type is int, then why it doesn’t accept the direct numbers or any other int variable except those three.

In java, enum is known concept, and in many cases you can use it, but for android, enum is something you should avoid to use as it’s processing performance is not efficient, so in Android performance patterns it’s told to avoid enums and to use annotations like @IntDef and @StringDef.



For example, you are working on a library that make user choose photo from gallery and camera and you are passing int value in your library method and taking argument in int. Then, based upon that value, you are opening camera or gallery.

class MyPicLibrary
{
    public static void pickPhoto(int source)
    {
        if (source == 0)
        {
            // Camera intent goes here
        }
        else if (source == 1)
        {
            // Gallery intent goes here
        }
    }
}

We can create static final int variables with names like CAMERA = 0 and GALLERY = 1 to make things easier to read and understand, but that will still give developers to pass any kind of int value in the pickPhoto() method. But, our goal is to restrict the developers to only pass values through our assigned names as its happening with View.setVisibility() method.

For this purpose, android has @IntDef and @StringDef annotations. Here’s a simplest example how previously described problem can be made easy with @IntDef.

class MyPicLibrary
{
      @Retention(RetentionPolicy.SOURCE)                    //declare retention policy source i.e complile time
      @IntDef({OPEN_CAMERA, OPEN_GALLERY})                  // @IntDef value allocation 

      //Declare interface which we gonna use as our custom annotation 
      public @interface ImageSource { }

      // Must be static final int values for IntDef
      public static final int OPEN_CAMERA = 0;
      public static final int OPEN_GALLERY = 1;

      private int source;

      //As setImageSource has argument type of @ImageSource, parameters passed can only be one of both
      // OPEN_CAMERA or OPEN_GALLERY
      public void setImageSource(@ImageSource int source){
          this.source = source;
      }

      @ImageSource
      public int getImageSource(){
          return OPEN_CAMERA || OPEN_GALLERY;   //Here you can't return simple integer value, It will generate compile time error
      }
      
      public static void pickPhoto(@ImageSource int source)
      {
          if (source == OPEN_CAMERA)
          {
              // Camera intent goes here
          }
          else if (source == OPEN_GALLERY)
          {
              // Gallery intent goes here
          }
      }
}


The important topic here to understand is why we are not using enums? Although you can use it for similar purposes but they are not as memory efficient as static final int constants. Here’s a nice video of performance optimization discussing the similar topic by Google below.


If you liked this article, you can read my new articles below:


profile card
Wajahat Karim
🌍 Making the world a better place, one app at a time.
🔥 Google Developer Expert (GDE) in Android . 📱 Professional Android Developer with ~10 years experience. 💻 Creator of various Open Source libraries on Android . 📝 Author of two technical books and 100+ articles on Android. 🎤 A passionate Public Speaker giving talks all over the world.
Author's picture

Wajahat Karim

🔥 Google Dev Expert (GDE) in Android .
📱 Android Dev. 💻 Open Source Contributor . 📝 Technical Writer . 🎤 Public Speaker

Senior Android Developer

Karachi, Pakistan