Android Studio最速入門~効率的にコーディングするための使い方

第40回分析機能について

はじめに

今回は地味ながらもあなどれない分析機能――「Analyze」メニューについて紹介します。⁠Analyze」メニューは図1のようなコマンドで構成されています。

図1 ⁠Analyze」メニューの内容
図1

"Infer Nullity..."まではインスペクション系の機能で、それ以降が分析系の機能になっています。まずはインスペクション系の機能について紹介します。

インスペクションについて

第14回で紹介したインスペクションはいわゆる on the fly(その場で指摘)系のもので、インテンションと異なり解決策の提案はほとんど行いません。そのためもあって、ともすれば小うるさいだけの機能に受け取られがちです。

しかし「Analyze」メニューにある"Inspect Code..."を実行すると「Inspectionツールウィンドウ」にインスペクション結果が出力されます。ちょうど検索("Find in Path")やリファクタリング・プレビューの「Findツールウィンドウ」に若干似ています。

図2 "Inspect Code..."の実行例(クリックすると動きがわかります)

「Inspectionツールウィンドウ」は左側のペインに、インスペクションで該当した箇所がカテゴリ別に分類されてリストアップされます。分類はツールバーで多少カスタマイズすることができます(詳しくは後述します⁠⁠。右側のペインには、左側で選択した対象の詳細(該当ファイル名やインスペクションに該当した理由など)が表示されます。

この「Inspectionツールウィンドウ」の特筆すべき点は、ツールバーにある Apply a quickfix」です。このアイコンをクリックすると、インスペクションに引っかかった対象に然るべき解決策を適用します。

図3 ⁠Apply a quickfix」ボタンで問題を解決する
図3 「Apply a quickfix」ボタンで問題を解決する

すべてのインスペクションに対して解決策が付くわけではありませんが、インスペクション結果を俯瞰して対応を施せる点が 第14回 で紹介した方法と異なります。

なお「Apply a quickfix」を実行したときにポップアップされる修正候補は「Inspectionツールウィンドウ」右側の詳細ペインに表示している「Problem resolution」と同じものです。

図4 ⁠Accept Resolution」ポップアップから解決策を選ぶ
図4

この「Problem resolution」のリンクをクリックしても解決策の適用になりますが「Apply a quickfix」は左側ペインの選択箇所に応じて、広範囲に解決策を適用できます。

参考までに「Inspectionツールウィンドウ」のツールバーの機能を表1に示します(⁠⁠Findツールウィンドウ」ツールバーと同じ機能のものは省略しています⁠⁠。

表1 ⁠Inspectionツールウィンドウ」のツールバーのリスト(一部抜粋)
アイコン機能
Exportインスペクション結果をHTMLかXMLにエクスポートします。XMLでエクスポートした結果は "View Offline Inspection Results..."で再表示できます。
Group by Severityインスペクション結果を重要度別に分類します。
Group by directoryインスペクション結果をディレクトリ別に分類します。
Filter resolved items解決済みの対象を除外(フィルタリング)します。
Show diff Rerun Inspection」で再度インスペクションを実行したときに前回との違いを表示します(字の色が変わる⁠⁠。
Show diff onlyおなじく、再度インスペクションを実行したときに、前回と変わらない結果を隠します。……とはヘルプにあるますが、正直「Show Diff」⁠Show diff only」の振る舞いはイマイチ納得できていません。
Edit settings該当するインスペクションの設定画面を開きます。
Apply a quickfixインスペクションに対応する解決策を適用します。
Hectorおじさん特定のコマンド名はありません。該当するインスペクション項目の有効/無効を設定します。クリックするとポップアップが表示されます。

その他のインスペクション系メニューについて

"Inspect Code..."以外にあと3つあるインスペクション系メニューについて紹介します。

Run Inspection by Name...
特定のインスペクション項目を名前を指定して実行します。
図4 ⁠Enter inspection name」ポップアップ
図4
"Find Action"や"Search Everwhere"のようなポップアップウィンドウから実行したいインスペクション名を指定するのですが、正直なところインスペクションを個別に覚えていられないので、ほとんど使った事はありません。ただインスペクションのセット(プロファイル)を作らず実行できるので、年に数回程度役に立つときがあります。
Configure Current File Analysis...
現在エディタで開いているファイルのインスペクションのレベルを設定します。ステータスバーの Hectorおじさん」をクリックしたのと同じです。
図6 "Configure Current File Analysis..."の実行例
図6
本稿を執筆していて明確になったのですが、ステータスバーのHectorおじさんも含めて、この設定の対象は現在編集中のファイルだけになります(面倒なことに「Power save mode」だけ全体に対して有効です⁠⁠。
ただし、その設定はリアルタイムインスペクションにだけ有効です。インスペクションのレベルと言っても正しくは「Highlighting Level(コードハイライトのレベル⁠⁠」なので、仮にその設定値を「None(なにもしない⁠⁠」にしても、"Inspect Code..."や"Run Inspection by Name..."の評価対象になります。
View Offline Inspection Results...
「Inspectionツールウィンドウ」から Export」を実行し、XML形式で保存しておいたインスペクション結果を再表示します。インスペクションのプロファイルによっては、"Inspect Code..."は非常に時間がかかるし、その結果もAndroid Studioを終了すると消えてしまいます。そのため、このオフラインブラウズは意外と重宝します。

Eclipseのクリーンアップとの比較

唐突ですが、Eclipseとの機能比較について語ります。Eclipseには「クリーンアップ」というコードを整理する便利な機能があります。

図10 Eclipseの「クリーンアップ」コマンド
図10

EclipseからAndroid Studioに移行した人のうち幾人かは、このクリーンアップに相当する機能を探して見つけられず落胆しているようです。結論から言えば、Android StudioにEclipseのクリーンアップに合致する機能はありません

その代わり先ほど紹介したインスペクション機能をうまく活用することで、クリーンアップに類似した事を実現できます。次からEclipseのクリーンアップの個々の設定に対応するAndroid Studioのインスペクタを紹介します。見出しは図11のクリーンアップ設定のタブ名で、文中の『』はインスペクタの項目を指します。中にはインスペクタで対応できない項目もあるので、代替策があれば都度補足します。

図11 Eclipseのクリーンアップのプロファイル設定画面
図11
※プロジェクトプロパティからJavaコード・スタイル→クリーンアップで、プロファイルの「編集」をクリック

コード・スタイル

「制御ステートメント」グループについては以下の通りです。

if/while/for/do ステートメントでブロックを使用
今回の「Analyze」メニューのカバー範囲ではなく、まだ紹介していないコードフォーマットでカバーします。具体的には「Preferences / Code Style」「Wrapping and Braces」で指定して、リフォーマット("Reformat Code...")します。
オプションの「常時」に相当するのは『Code style issues / Control flow statement without braces』です。
forループを拡張に変換
『Java language level migration aids / 'for' loop replaceable with 'for each'』が相当します。

「式」グループについては以下の通りです。

式で括弧を使用
オプションの「常時」に相当するのは『Code style issues / Unclear expression』です。もう一方の「必要な場合のみ(不要な括弧を除去⁠⁠」に相当するのは『Code style issues / Unnecessary parentheses』です。

「変数宣言」グループについては以下の通りです。

使用可能な場合、修飾子 'final' を使用(privateフィールド、パラメータ、ローカル変数)
『Code style issues / Field may be final』『Code style issues / Local variable or parameter can be final』が相当します。
この逆(不必要な finalを除去する)のことを行う『Code style issues / Unnecessary 'final' on local variable or parameter』という項目もあります。

コード編成

「フォーマッター」グループについては以下の通りです。

ソース・コードのフォーマット
「Analyze」メニュー(インスペクション)のカバー範囲ではありません。コード整形は"Reformat Code..."で行います。
末尾の空白の除去
「Analyze」メニュー(インスペクション)のカバー範囲ではありません。エディタの設定です。⁠Preferences / Editor」設定画面にある「Strip trailing spaces on Save」でファイル保存時の振る舞いとして空白の除去を指定します。指定できるオプションは「Modified Lines(変更行だけを対象にする⁠⁠/All(すべての行を対象にする⁠⁠/None(空白の除去を行わない⁠⁠」の3つです。
インデントの訂正
これも「Analyze」メニュー(インスペクション)のカバー範囲ではなく、コード整形時に行われます。その内容は「Preferences / Code Style」設定画面の設定に従います。Eclipseでいうところの「インデント訂正をしない」はAndroid Studioでは指定できません。

「メンバー」グループについては以下の通りです。

メンバーのソート
「Analyze」メニュー(インスペクション)のカバー範囲ではありません。コード整形のひとつのアレンジメント("Rearrange Code")時に実施されます。その内容は「Preferences / Code Style」設定画面のアレンジメント設定に従います。

メンバー・アクセス

「非静的アクセス」グループについては以下の通りです。

フィールド・アクセスに 'this' 修飾子を使用
メソッド・アクセスに 'this' 修飾子を使用
上の2つは同じ設定で適用されます。Eclipseのように別々に扱うことはできません。オプションの「必要な場合のみ」に相当するのは『Code style issues / Unnecessary 'this' qualifier』で、もうひとつの「常時」に相当するのは『Code style issues / Instance field access not qualified with 'this'』『Code style issues / Instance field access not qualified with 'this'』です。

「静的アクセス」グループについては以下の通りです。

宣言されているクラスを修飾子として使用
直接対応する項目はありません。面倒ですが『Imports / Add Single-Member Static Import』『Add On Demand Static Import』staticインポート化したのち『Imports / Expand Static Import』で再展開すると期待通りの結果になります。
ちょっと毛色が違いますが「無駄なstaticアクセスを除去する」という項目(⁠⁠Code style issues / Unnecessarily qualified static access⁠⁠)もあります。
フィールド・アクセスの修飾
メソッド・アクセスの修飾
この2つをあわせた項目に『Code style issues / Unqualified static access』があります。
サブタイプを介するすべてのアクセスの変更
『Probable bugs / Static field referenced via subclass』『Probable bugs / Static method referenced via subclass』が相当します。
インスタンスを介するすべてのアクセスの変更
『General / Access static member via instance reference』が相当します。

欠落コード

「注釈」グループについては以下の通りです。

'@Override' と インターフェース・メソッドの実装 (1.6以上)
『Class structure / Missing @Override annotation』が相当します。
'@使用すべきではない'
この設定の意味は@Deprecated を適切に使う」という項目です。⁠Class structure / Missing @Deprecated annotation」が相当します。

「潜在的なプログラミングの問題」グループについては以下の通りです。

シリアル・バージョン ID の追加
『Serialization issues / Serializable class without 'serialVersionUID'」が相当します。ただし、Eclipseのように '1L' を設定することはできません。

「未実装コード」グループについては以下の通りです。

実装されていないメソッドの追加
これはそもそもコンパイルエラーになるので、これといった設定項目はありません。

不要なコード

「未使用コード」グループについては以下の通りです。

未使用のインポートの除去
『Imports / Unused import』が相当します。
未使用の private メンバーの除去(タイプ、コンストラクター、フィールド、メソッド)
未使用のローカル変数を除去
上の2つをあわせて『Declaration redundancy / Unused symbol』が相当します。オプションでチェックする対象を「Check Classes(クラス⁠⁠/Check Fields(フィールド⁠⁠/Check Local Variables(変数⁠⁠/Check Methods(メソッド⁠⁠/Check Parameters(引数⁠⁠」の5つから選択します。

「不要なコード」グループについては以下の通りです。

不要なキャストの除去
『Verbose or redundant code constructs / Redundant type cast』が相当します。
不要な '$NON-NLS$' タグを除去
かろうじて言えば『Internationalization issues / Hard coded strings』が相当します。オプションの「Ignore lines containing this comment」に無視させたいコメントキーワードを設定できます(Android StudioのデフォルトではNON-NLSです⁠⁠。

分析系のコマンドについて

続いての機能が分析系の機能です。インスペクションに押され気味ですが「Analyze」メニューの本命はこちらです(と思ってます⁠⁠。

依存関係の分析

コード、モジュールなどの依存関係の分析を行います。身もフタも無い紹介をするとJDependみたいなもの」です。Android Studioで用意しているコマンドは以下の通りです。

Analyze Dependencies...
クラスやライブラリ、モジュールの依存関係(順方向:親→子)を分析します。
Analyze Backward Dependencies...
クラスやライブラリ、モジュールの依存関係(逆方向:子→親)を分析します。分析したい対象(クラスやパッケージ、ライブラリ)を選択し、コマンドを実行することで、それに依存している対象を探し出します。順方向の分析に比べて時間がかかります。
Analyze Module Dependencies...
モジュール間の依存関係(順方向:親→子)を分析します。この分析だけ(後述する)⁠Dependency Viewerツールウィンドウ」ではなく「Module Dependenciesツールウィンドウ」が右側に表示されます。ただ、それほど使い道はないでしょう……。
Analyze Cyclic Dependencies...
パッケージやライブラリ、モジュールの循環参照関係を分析します。主にパッケージ間の依存関係を探るのに用います。

"Analyze Dependencies..."は特にどこかを指定しなくても使えるコマンドですが、Androidプロジェクトは自動生成したコードがあったりと、通常のJavaプロジェクトより複雑なので、図12のようにソースディレクトリを指定して分析することをオススメします。

図12 ソースディレクトリを指定して"Analyze Dependencies..."を実行する
図12

依存関係の分析が完了すると「Dependency Viewerツールウィンドウ」にその結果が表示されます("Analyze Module Dependencies..."は除く⁠⁠。このツールウィンドウは3つの区画(ペイン)から成り立っています。

Analyzed Codeペイン
ツールウィンドウの左上部分です。分析の対象となったクラスやパッケージがリストアップされます。この中のどれかを選択すると、それと依存関係のあるものが右隣の「Parent Codeペイン」に表示されます。
Parent Codeペイン
ツールウィンドウの右上部分です。⁠Analyzed Codeペイン」で選択中のノード(クラスやパッケージ)に依存しているオブジェクトがリストアップされます。さらに、ここのどれかを選択すると、使用箇所の詳細が下の「Usageペイン」に表示されます。
Usageペイン
「Analyzed Codeペイン」「Parent Codeペイン」で選択したノード(クラス)の使用箇所をリストアップします。左端のツールバーにある Preview」をONにすると右側に「Usageペイン」で選択したノードに該当するソースコードをプレビューします。
図13 ⁠Dependency Viewerツールウィンドウ」の例
図13

では、"Analyze Dependencies..."を例に、実際の使い方を紹介します。説明を簡単にするため、図14のような構造のクラス群(ソースコードはリスト2 のとおり)を例にします。

図14 依存関係の分析に用いるクラス群
図14
リスト2 依存関係の分析に用いるクラス群のソースコード
public class A {
  private B b;
  private C c;
}

public class B {}

public class C {
  private A a;
}

public class D extends A { }

"Analyze Dependencies..."を実行すると順方向(親→子)の依存関係が「Dependency Viewerツールウィンドウ」にリストアップされます。とは言え、それを眺めているだけでは楽しくもなんともありません。この機能の真骨頂は依存関係にルールを適用する事にあります。

仮に「クラスAはクラスBを使ってはいけない」というルールを適用したい場合、図15のように「Analyzed Codeペイン」「Parent Codeペイン」でそれぞれのクラスを指定した状態でツールバーにある Mark Illegal」をクリックします。

図15 クラスAはクラスBに依存しているが、それを禁止したい
図15

すると「クラスAはクラスBを使ってはいけない」がルールとなり、以降エディタ上では図16のようにインスペクションの警告対象となります。

図16 クラスAがクラスBを使うのは依存性違反
図16

これはインスペクションの『General / Illegal package dependencies』が行っている検査で、先ほどの Mark Illegal」で、この検査項目のオプション(Configure dependency rules)を指定したわけです。この依存関係のルールは Edit Rules」でより細かく指定することができます。

図17 ⁠Dependency Validation」ダイアログ
図17

「Dependency Validation」ダイアログは禁止と許可の2つの方法で依存関係のルールを定義できます。

禁止するルール
「Deny usages of」に対象を、⁠in」に依存してほしくない利用箇所を指定します。先ほどの例では「Deny usage of クラスB in クラスAという指定になります。
許可するルール
禁止とは逆に「ここでだけ利用を許可する」というルールです。⁠Allow usages of」に対象を、⁠only in」にここでだけ利用してほしい箇所を指定します。
たとえば「クラスAはクラスDだけ使って良い」とするならば「Allow usages of クラスA only in クラスDとします。この場合、クラスCが依存性違反で警告されます。
図18 ⁠クラスAはクラスDしか使えない」のでクラスCが警告される
図18

なお「Dependency Validation」ダイアログに指定する対象はスコープ(scopes)なので、特定のクラスだけではなく、もっと多彩なパターン(特定のパッケージとか、特定の接頭子や接尾子など)で指定することができます。

"Analyze Backward Dependencies..."の場合は、図19のように依存される側を選択してから実行するのがポイントです。

図19 "Analyze Backward Dependencies..."の実行例
図19

たとえばクラスAに対して実行すると、クラスAに依存しているのはクラスCとクラスDということがわかります。

図20 クラスAに対する"Analyze Backward Dependencies"の実行結果
図20

"Analyze Cyclic Dependencies..."はパッケージ同士の循環参照関係を分析します。先ほどの例はすべて同じパッケージに存在するため、このコマンドを実行しても何も結果がでません。それでは面白くないので、クラスCを別パッケージに移動してから実行してみると図21のような結果になります。

図21 "Analyze Cyclic Dependencies"の実行結果
図21

データフローの分析

個人的にはAndroid Studio(やIntelliJ IDEA)の自慢機能のひとつだと思っている「データフロー分析」です。この機能を用いることで、次のような分析を行うことができます。

  • 変数やパラメタに代入される値がどこからくるか
  • 変数がもつ可能性のある値のリストアップ
  • 変数にnullが代入される可能性
  • 式や変数が、このあとどう使われるか
Analyze Data Flow to Here
「ここまで」データがどう流れてきたかを分析します。変数やフィールド、メソッドのパラメタにカーソルを置き "Analyze Data Flow to Here" を実行すると、データの流れを追ってその対象にどのような値が代入され得るかをリストアップします。
図22はあるメソッドのパラメタtitleに対して "Analyze Data Flow to Here"を実行した例です。
図22 "Analyze Data Flow to Here"の実行例
図22
これだけでもパラメタに設定し得る値と、その流れがわかります。さらにツールバーの Group by leaf expression」 Group by leaf expression nullness」で、この結果をグループ化することができます。
Group by leaf expression」を押すと、結果を代入し得る値(または式)別にグループ化します。
図23 ⁠Group by leaf expression」でグループ化した例
図23
※各ノードのトップにある「Value:?」が、このパラメタに代入し得る値になります
もうひとつの Group by leaf expression nullness」は、さらにnull値を取り得るか」でグループ化します。
図24 ⁠Group by leaf expression nullness」でグループ化した例
図24
Analyze Data Flow from Here
「ここから」データがどう流れていくかを分析します。変数やフィールド、メソッドの戻り値にカーソルを置き "Analyze Data Flow from Here" を実行すると、その対象がその後、どのように利用されているかをリストアップします。
図25 "Analyze Data Flow from Here"の実行例
図25
※あいにくAndroid Studioには、この例に適したサンプルコードがなかったので、IntelliJ IDEAでの実行例です。

スタックトレースの分析

"Analyze Stacktrace..."のことです。割りとしょうもない系の機能ですが、この機能は外部から提供されたスタックトレースを分析する機能です。たとえばテストをしているとき、自分以外の人がバグを見つけて、その時のログとしてスタックトレースをメールやバグトラッキングシステムに添付したとしましょう。この「外部の」スタックトレースは単なるテキストなので、スタックトレースから該当のソースコードへジャンプする事はできません。当たり前ですね。

しかし"Analyze Stacktrace..."を通すことで、スタックトレースにリンクできるソースコードを割り当て「Runツールウィンドウ」「Debugツールウィンドウ」と同じようにソースコードへジャンプできるようにします。他にもスレッドダンプが含まれていれば、それを解析したログビューを表示します。

"Analyze Stacktrace..."を実行すると図26のような「Analyze Stacktrace」ダイアログが表示されるので「Put a stack trace or a complete thread dump here:」の下にあるテキストエリアにスタックトレースを貼り付けて下さい。

図26 ⁠Analyze Stacktrace」ダイアログ
図26
※IntelliJ IDEAではスクランブルがかかったスタックトレースを解読する機能(Unscramble stacktrace)がありますが、これはAndroid Studioでは使えません

貼り付けたスタックトレースが、ここに辿り着く間にテキスト処理でラインカットやワードラップされている場合は「Normalize」ボタンで復元を試みて下さい。⁠OK」ボタンを押すと「Runツールウィンドウ」にこのスタックトレースが(可能ならば)ソースコードへのリンク付きで表示されます。

まとめ

Android Studioの分析機能は地味な存在ながら便利な機能が揃っています。他のIDEではなかなかお目にかからない機能という事も相まって、Android Studioを特徴付けている機能のひとつだと筆者は思っています。

なかなか奥深く使いこなすのは簡単ではありませんが、筆者に「Javaでもいいや」ではなく「Javaがいい」と思わせるくらいに強力な機能です。

おすすめ記事

記事・ニュース一覧