web-dev-qa-db-ja.com

Android-@IntDef値を@interface内に配置しても問題ありませんか?

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;

ただし、1つのファイルに複数の定義(UserType、StoreTypeなど)がある場合、状況は非常に複雑になります。

2番目の方法:定義間で値を分離するために、次のようなものを思いつきました:

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;

しかし、ご覧のとおり、2つの異なる名前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内に配置しても問題ありませんか?上記の3つの方法でパフォーマンスに違いはありますか?

42
Ahmad Fadli

短い回答:単純なプロジェクトの場合は問題ありませんが、より複雑なプロジェクトの場合は、最初の方法が推奨されます。

長い答えsortTypeのバイトコードは3つのケースすべてで同じですが、違いがあります。キーは、保持ポリシーをRetentionに設定するSOURCEアノテーションにあります。つまり、SortTypeアノテーションは " コンパイラによって破棄される "であるため、アノテーション自体のバイトコードは生成されません。

最初の方法では、アノテーションの外側に通常の静的フィールドを定義し、それらのために通常のバイトコードを生成します。 2番目と3番目のケースは、アノテーション内の定数を定義し、定数のバイトコードは生成されません。

コンパイラがSortType宣言を含むソースファイルにアクセスできる場合、どちらの方法でも問題はなく、sortTypeのバイトコードは同じです。ただし、ソースコードにアクセスできない場合(たとえば、コンパイル済みのライブラリしかない場合)、注釈にはアクセスできません。最初の方法では、注釈自体にアクセスできませんが、後者の方法では、定数値にもアクセスできません。

最もクリーンで構造化された方法として、3番目の方法を好んで使用していました。以前は、ある日まで問題に遭遇していました。そのコードのEspressoテストを書き始めたとき、コンパイラーは注釈を定義するソースコードにアクセスできませんでした。テストでは、正規のIntDef宣言に切り替えるか、記号定数の代わりに整数値を使用する必要がありました。

したがって、最終的には次のようになります。

  • アノテーションがコードの内部にあり、テストを含む他の場所から参照しない限り、標準的な方法に固執する
10

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;

どちらを選択しても、どちらも機能するはずです。

4

Android docsがあなたの最初の方法を示している理由を見つけたいと思ってここに来ましたが、3番目の方法は数か月間、製品コードでうまく機能しています。言ったように、関連する定数のセットが複数ある場合は、名前空間をクリーンアップします。

1
TBridges42

列挙型には良い場所のようです...

public enum SortEnum {
    DURATION,
    PRICE,
    TIME;
}
0
NinePlanFailed