Android - Is it ok to put @IntDef values inside @interface? Android - Is it ok to put @IntDef values inside @interface? android android

Android - Is it ok to put @IntDef values inside @interface?


Short answer: for simple projects, it is OK, but for more complex ones the first method is preferred.

Long answer: Although bytecode for sortType is identical in all three cases, there is a difference. The key lies in the Retention annotation, which sets retention policy to SOURCE. That means that your SortType annotation is "to be discarded by the compiler", so bytecode for annotation itself is not generated.

First method defines regular static fields outside the annotations, with the regular bytecode generated for them. Second and third cases define constants within annotations, and bytecode for the constants is not generated.

If compiler has access to the source file containing your SortType declaration, either method is fine and bytecode for sortType is identical. But if source code is not accessible (e.g. you have only compiled library), annotation is not accessible. For the first approach, only annotation itself is not accessible, but for the latter ones, constants values are not accessible too.

I used to prefer the third method as the most clean and structured. I used to until one day I ran into an issue: when I started writing Espresso tests for that code, compiler did not have access to the source code defining the annotation. I had to either switch to the canonical IntDef declaration or to use integer values instead of symbolic constants for the test.

So the bottom line is:

  • stick to the canonical way unless your annotation is internal to your code and you do not refer to it from anywhere else, including tests


To make your third method working, you should name values like in the interface.I used your code and make it works:

public class Constant {    @IntDef(value = {SortType.PRICE, SortType.TIME, SortType.DURATION})    @Retention(RetentionPolicy.SOURCE)    @interface SortType {        int PRICE = 0;        int TIME = 1;        int DURATION = 2;    }}

Or

public class Constant {    @IntDef(value = {SortType.SORT_PRICE, SortType.SORT_TIME, SortType.SORT_DURATION})    @Retention(RetentionPolicy.SOURCE)    @interface SortType {        int SORT_PRICE = 0;        int SORT_TIME = 1;        int SORT_DURATION = 2;    }}

Usage for second:

@Constant.SortType int sortType = Constant.SortType.SORT_DURATION;

Pick one, both should work.


I came here hoping to find why the Android docs show your first method, but the third method has been working fine for me in production code for months. I haven't seen any reason not to do it that way. As you said, it cleans up the namespace when you might have multiple sets of related constants.