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つの異なる名前SortTypeDef
とSortType
を作成しました
番目の方法:可能な値のリストを@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つの方法でパフォーマンスに違いはありますか?
短い回答:単純なプロジェクトの場合は問題ありませんが、より複雑なプロジェクトの場合は、最初の方法が推奨されます。
長い答え:sortType
のバイトコードは3つのケースすべてで同じですが、違いがあります。キーは、保持ポリシーをRetention
に設定するSOURCE
アノテーションにあります。つまり、SortType
アノテーションは " コンパイラによって破棄される "であるため、アノテーション自体のバイトコードは生成されません。
最初の方法では、アノテーションの外側に通常の静的フィールドを定義し、それらのために通常のバイトコードを生成します。 2番目と3番目のケースは、アノテーション内の定数を定義し、定数のバイトコードは生成されません。
コンパイラがSortType
宣言を含むソースファイルにアクセスできる場合、どちらの方法でも問題はなく、sortType
のバイトコードは同じです。ただし、ソースコードにアクセスできない場合(たとえば、コンパイル済みのライブラリしかない場合)、注釈にはアクセスできません。最初の方法では、注釈自体にアクセスできませんが、後者の方法では、定数値にもアクセスできません。
最もクリーンで構造化された方法として、3番目の方法を好んで使用していました。以前は、ある日まで問題に遭遇していました。そのコードのEspressoテストを書き始めたとき、コンパイラーは注釈を定義するソースコードにアクセスできませんでした。テストでは、正規のIntDef
宣言に切り替えるか、記号定数の代わりに整数値を使用する必要がありました。
したがって、最終的には次のようになります。
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;
どちらを選択しても、どちらも機能するはずです。
Android docsがあなたの最初の方法を示している理由を見つけたいと思ってここに来ましたが、3番目の方法は数か月間、製品コードでうまく機能しています。言ったように、関連する定数のセットが複数ある場合は、名前空間をクリーンアップします。
列挙型には良い場所のようです...
public enum SortEnum {
DURATION,
PRICE,
TIME;
}