Android Studio にはコードチェックツール Lint が内蔵されており、メニューバーから Analyze > Inspect Code を選択して対応するコードチェックを実行できます。コードチェックは、不正な潜在的問題を推測に基づいて検出することができ、開発段階で開発者が管理上の理由で引き起こしたコードの問題を発見するのに役立ちます。Android 公式は、開発者が問題を早期に発見できるようにするために、注釈ライブラリ support-annotations を提供しています。以下は一般的に使用される注釈のいくつかで、主な内容は次のとおりです:
- Nullness 注釈
- リソース注釈
- スレッド注釈
- 値制約注釈
- 権限注釈
- 戻り値注釈
- CallSuper 注釈
- Typedef 注釈
- 可視性注釈
Nullness 注釈#
Nullness 注釈を使用すると、指定された変数、パラメータ、および戻り値が null 値を許可するかどうかをチェックできます。具体的には次のとおりです:
- @Nullable :null である可能性がある変数、パラメータ、または戻り値を示します。
- @NonNull :null であってはならない変数、パラメータ、または戻り値を示します。
@NonNull
@Override
public View onCreateView(String name, @NonNull Context context,@NonNull AttributeSet attrs) {
//...
}
リソース注釈#
リソース注釈を使用すると、ソースコード段階でエディタが不規則な書き方をチェックでき、ある程度コード構造を最適化できます。以下は一般的なリソース注釈です:
- @StringRes:R.string 参照が含まれているかどうかをチェックします。
- @ColorRes:R.color 参照が含まれているかどうかをチェックします。
- @ColorInt:色を表す整数が含まれているかどうかをチェックします。
- @DrawableRes:R.drawable 参照が含まれているかどうかをチェックします。
- @DimenRes:R.dimen 参照が含まれているかどうかをチェックします。
- @InterpolatorRes:補間器の参照が含まれているかどうかをチェックします。
スレッド注釈#
スレッド注釈は、特定のタイプのスレッドからメソッドが呼び出されているかどうかをチェックできます。以下のスレッド注釈をサポートしています:
- @MainThread:主スレッドを示します。
- @UiThread:UI スレッドを示します。
- @WorkerThread:作業スレッドを示します。
- @BinderThread:Binder スレッドを示します。
- @AnyThread:任意のスレッドを示します。
上記の注釈の中で @MainThread と @UiThread はほとんどの場合同じスレッドを示します。アプリケーションに複数のビューがある場合、UI スレッドは主スレッドと異なることがあるため、@UIThread を使用してアプリのビュー階層に関連するメソッドをマークできます。@MainThread はアプリのライフサイクルに関連するメソッドをマークするためにのみ使用されます。スレッド注釈の最も一般的な用途は、AsyncTask の使用中のメソッドの置き換えです。AsyncTask はバックグラウンド操作を実行し、結果を UI スレッドに公開します。
値制約注釈#
値制約注釈を使用すると、渡されたパラメータの値の合法性を検証できます。これにより、パラメータの設定範囲を指定でき、主観的なエラーをある程度減らすことができます。一般的な値制約注釈は次のとおりです:
- @IntRange:整数パラメータが指定された範囲内にあるかどうかを検証できます。
- @FloatRange:浮動小数点パラメータが指定された範囲内にあるかどうかを検証できます。
- @Size:コレクション、配列、文字列パラメータが指定された範囲内にあるかどうかを検証できます。最大値、最小値、正確な値を指定できます。
上記の注釈には、from、to、min などの使用可能なパラメータがあります。使用時には、特定の注釈の定義を確認してください。
権限注釈#
権限注釈 @RequiresPermission は、メソッド呼び出し元の権限を検証できます。つまり、権限注釈を使用したメソッドを呼び出すと、指定された権限があるかどうかがチェックされ、権限がない場合は AndroidManifest.xml ファイルに権限を宣言する必要があることが通知されます。危険な権限の場合は、動的に権限を要求する必要があります。使用方法は以下の通りです:
/**
* 単一権限チェック
* @param message
*/
@RequiresPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
public void setMessage(String message) {
}
/**
* すべての権限チェック
* @param message
*/
@RequiresPermission(allOf = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE})
public void setMesage(String message) {
}
/**
* 特定の権限チェック
* @param message
*/
@RequiresPermission(anyOf = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE})
public void setMesage(String message) {
}
戻り値注釈#
戻り値注釈 @CheckResult は、特定のメソッドの戻り値が使用されているかどうかをチェックします。使用されていない場合、suggest 設定に基づいて、戻り値がない別のメソッドを使用することを提案します。戻り値が使用されている場合は、注釈が付いていないメソッドと同じように扱われます。使用方法は以下の通りです:
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
public int checkPermission(@NonNull String permission, int pid, int uid){
return 0;
}
戻り値が使用されていない場合、次のように通知されます:
戻り値が使用されていない場合、同じ機能を持つ戻り値のない別のメソッドを使用することを提案します。要するに、戻り値注釈 @CheckResult は、メソッドが実際に使用されるのがメソッド自体の処理なのか、メソッドの最終的な処理結果なのかを示すことができます。
CallSuper 注釈#
@CallSuper 注釈を使用すると、サブクラスのオーバーライドメソッドが親クラスの実装を呼び出しているかどうかを検証します。この制約の利点は、親クラスの実装が変更されないことを保証できることです。もちろん、この注釈を使用しない場合、サブクラスが親クラスのメソッドをオーバーライドしても、親クラスのデフォルト実装を呼び出さなくてもかまいません。具体的には以下の通りです:
/**
* 親クラス
* @CallSuper 注釈の使用
*/
public class Test {
// @CallSuper 注釈を使用すると、サブクラスがこのメソッドをオーバーライドする際に必ずこのメソッドを呼び出す必要があります。
@CallSuper
protected void onCreate(){
}
}
以下は Test クラスの実装クラスです:
/**
* サブクラス
* @CallSuper 注釈の使用
*/
public class TestImpl extends Test{
@Override
protected void onCreate() {
super.onCreate();
/**
* 親クラスのメソッドを呼び出さない場合、次のように通知されます。
* Some methods, such as View#onDetachedFromWindow, require that you also call the super implementation as part of your method.
*/
}
}
Typedef 注釈#
@IntDef と @StringDef 注釈 を使用すると、他のコードで使用される特定の整数および文字列を検証するための整数および文字列の列挙注釈を作成できます。これにより、コード内の特定の定義された定数セットであることを保証できます。これらの二つの注釈は、注釈の位置にのみ使用できます。
開発中には列挙を使用することが多く、列挙はコード構造をより明確にするのに役立ちますが、列挙の使用はメモリのオーバーヘッドを増加させます。ここでは、Typedef 注釈の方法を使用して列挙を置き換えることができます。以下は Typedef 注釈の使用例です:
/**
* Typedef 注釈の定義
*/
public class ActionType {
public static final int ACTION_TYPE_0 = 0;
public static final int ACTION_TYPE_1 = 1;
public static final int ACTION_TYPE_2 = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ACTION_TYPE_0,ACTION_TYPE_1,ACTION_TYPE_2})
public @interface ActionTypeDef{
}
}
以下は上記の Typedef 注釈の使用方法です:
/**
* Typedef 注釈の使用
* @param value
*/
private void setValue(@ActionType.ActionTypeDef int value) {
switch (value) {
case ActionType.ACTION_TYPE_0:
break;
case ActionType.ACTION_TYPE_1:
break;
case ActionType.ACTION_TYPE_2:
break;
// case 100://未定義の整数を使用することはできません
// break;
}
}
Typedef 注釈は、使用される特定の整数を制約します。もちろん、文字列も可能で、これにより列挙の効果を得ることができます。
可視性注釈#
可視性注釈は @VisibleForTesting と @Keep で、メソッド、フィールド、クラスの可視性を示すことができます。具体的には次のとおりです:
- @VisibleForTesting:注釈されたコードブロックの可視性がテストに必要なレベルを超えていることを示します。
- @Keep:注釈されたコードブロックが混乱しないことを示します。
最も一般的に使用されるのはリソース注釈で、例えば @StringRes、@ColorRes、@ColorInt などです。また、Typedef 注釈もあり、この注釈は列挙の置き換えにおいて Android 開発におけるパフォーマンスへの影響を軽減できます。普段からこれらの注釈が Android ソースコードでよく使用されていることに注意して、開発中にこれらの注釈を使用して必要なコードチェックを行うことをお勧めします。