Android Studio には、コードチェックツールである Lint が組み込まれており、メニューバーで Analyze > Inspect Code を選択することで、対応するコードチェックを実行することができます。コードチェックは、推論に基づいていくつかの不正な潜在的な問題を検出することができ、開発者が上司の要求によって引き起こされる可能性のあるいくつかのコードの問題を開発段階で発見するのに役立ちます。Android 公式では、開発者が問題を早期に発見するためにサポートアノテーションという注釈ライブラリを提供しています。以下に一部の一般的な注釈の内容を示します。
- 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** はアプリケーションのライフサイクルに関連するメソッドにマークすることができます。スレッド注釈の最も一般的な使用法の 1 つは、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 のソースコードでも頻繁に使用されているため、開発プロセスでこれらの注釈を使用して必要なコードチェックを行うことを試してみることができます。