Android - 将@IntDef值放在@interface中可以吗?

时间:2016-02-25 10:53:34

标签: java android annotations

我正在尝试在Android开发中实现@IntDef注释。

第一种方法:在Constant.java类中分隔定义看起来很棒:

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

用法:

@Constant.SortType int sortType = Constant.SORT_PRICE;

但是当一个文件中存在多个定义(例如UserType,StoreType等)时,事情会变得更加混乱。

第二种方法:所以我想出了这样的东西来区分定义之间的值:

public class Constant {
   @IntDef(value={SortType.SORT_PRICE, SortType.SORT_TIME, SortType.SORT_DURATION})
   @Retention(RetentionPolicy.SOURCE)
   public @interface SortTypeDef{}

   public static class SortType{
       public static final int PRICE = 0;
       public static final int TIME = 1;
       public static final int DURATION = 2;
   }
}

用法:

@Constant.SortTypeDef int sortType = Constant.SortType.PRICE;

但正如您所看到的,我为其创建了两个不同的名称:SortTypeDefSortType

第三种方法:我尝试在@interface内移动可能值列表:

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

用法

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

虽然它确实有效,但我不知道有什么缺点。 是否可以将@IntDef的可能值放在@interface内?上述三种方法之间是否有任何性能差异?

4 个答案:

答案 0 :(得分:10)

简短回答:对于简单项目,没关系,但对于更复杂的项目,首选方法是首选。

答案很长: 虽然sortType的字节码在所有三种情况下都是相同的,但是存在差异。关键在于Retention注释,它将保留策略设置为SOURCE。这意味着您的SortType注释是" to be discarded by the compiler",因此不会生成注释本身的字节码。

第一种方法定义注释之外的常规静态字段,并为它们生成常规字节码。第二种和第三种情况在注释中定义常量,并且不生成常量的字节码。

如果编译器可以访问包含SortType声明的源文件,则任何一种方法都可以,sortType的字节码是相同的。但是,如果无法访问源代码(例如,您只编译了库),则无法访问注释。对于第一种方法,只有注释本身不可访问,但对于后者,常量值也不可访问。

我曾经更喜欢第三种方法,因为它是最干净和最有条理的。我曾经有一天遇到过一个问题:当我开始为该代码编写Espresso测试时,编译器无法访问定义注释的源代码。我不得不切换到规范IntDef声明或使用整数值而不是符号常量进行测试。

所以底线是:

  • 坚持规范的方式,除非您的注释是代码内部的,并且您不会从其他任何地方引用它,包括测试

答案 1 :(得分:3)

要使第三种方法有效,您应该在界面中命名values。 我使用了你的代码并使其有效:

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

或者

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

第二种用法:

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

选择一个,两者都应该有用。

答案 2 :(得分:1)

我来到这里希望找到为什么Android文档显示你的第一个方法,但第三种方法在生产代码中已经好几个月了。我没有看到任何理由不这样做。正如您所说,当您可能有多组相关常量时,它会清理命名空间。

答案 3 :(得分:-1)

似乎是一个很棒的地方...

public enum SortEnum {
    DURATION,
    PRICE,
    TIME;
}