Android StudioのBreakpoints再入門


## はじめに

みなさん、Androidアプリのデバッグ時にアプリケーションコードにむやみに`Log.d()`を埋めて、再ビルドを何回も繰り返しながらデバッグしていませんか？
もしくはブレークポイントでsuspendさせまくって、`Resume Program`(suspend状態から再開するやつ)を連打していませんか？

でもアプリの規模が大きくなっていくと、再ビルドに掛かる時間も無視できなくなったり、`Resume Program`の連打し過ぎで指が腱鞘炎になったりします。

そんなときはAndroid StudioのBreakpointsを上手く設定して、何度も「再ビルド→再インストール」や`Resume Program`連打から脱却しましょう。

## 目標

* デバッグのために何度も「`Log.d()`を埋め込んでアプリを再ビルド→再インストール」をやめる
* `Resume Program`連打をやめる

## 環境

Android Studio3.5
Android 9(なんとなく)

## 「ブレークポイント」でログを出力する

実行時に通ったパスを知りたいけど、`Log.d()`を埋めて再ビルドを待つのは嫌。でも、ブレークポイントを張りまくって毎回処理がsuspendされるのは鬱陶しい…
そんな時はブレークポイントを上手に設定して、suspendさせること無くログを出力しましょう。

### 手順

1. いつも通り、対象の行にブレークポイントを張る
1. Breakpoints(デフォルトではShift + Command + F8) > 左の一覧から該当のブレークポイントを選択 > `Suspend`のチェックを外す
1. `"Breakpoint hit" message`にチェックを付ける (お好みでStack traceも出力できます)
1. `DONE`をクリック(**チェックボックスをクリックしただけだと反映されない**)

<img width="886" alt="breakpoint01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/cbaa743e-ccbc-4ae3-910e-95fd57d7d703.png">

ブレークポイントを設定したら、いつも通りデバッガをアタッチして実際に該当箇所の処理を実行するだけ。
該当する行が実行されると以下のようにログが出力されます。
**※LogcatではなくDebuggerのConsoleタブに出力されるので注意が必要です**

<img width="951" alt="logcat.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/4f97cb77-2f63-d24d-c3fb-193c6d76ef8a.png">

アプリを再ビルドすることなく` Breakpoint reached at net.fdash.adventcalendartest.MainActivity.onCreate(MainActivity.kt:22)`というログを出力させることが出来ました！

## ついでに変数の中身、関数の戻り値を出力したい

例えば、RecyclerViewのポジションやタップされた座標のようにどんどん変わっていく値を見るために、毎回ブレークポイントでsuspendさせて値を確認するのは効率が悪いですよね。
そんなときに↓のようなログを埋めてアプリを再ビルドしたことはありませんか？

```kotlin
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    Log.d(TAG, "${position}番目のセルにViewHolderがbindされたよ")
```

実はこの場合も、アプリを再ビルドすることなく実現できます。

### 手順

1. 先程と同様にsuspendさせないブレークポイントを設定する
1. `Evaluate and log:`にチェックを入れテキストボックスに表示させたい文字列を入れる(**コードの評価をしてくれるので、変数や関数呼び出しを含めることも可能**)
 
<img width="651" alt="ViewHolder01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/c58dc7e0-2dd7-4e1b-44a7-a99cec48d7fd.png">

あとは、同じようにデバッガをアタッチして該当するコードを実行するだけです。
アプリを再ビルドすることも、ViewHolderがbindされる度にsuspendされることもなく、何番目のセルにViewHolderがbindされたか知ることが出来ます。

<img width="458" alt="ViewHolder02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/dce0d285-cf60-1fc7-d637-fa77b41d3de3.png">

### ブレークポイントの条件いろいろ

ちなみに、ブレークポイントには細かく条件を設定することができます。

|項目|説明|
|----|----------|
|`Remove once hit`|初回到達時にブレークポイントが外れる|
|`Instance filters:`| 指定したインスタンスID (`MainActivity@10792`の`10792`の部分)のインスタンスでだけブレークポイントが有効になる|
|`Class filters:` |指定したクラスの場合だけブレークポイントが有効になる<br/>継承関係がある場合に、特定のサブクラスだけブレークポイントを有効(もしくは無効)などが可能|
|`Pass count:` |該当する行に指定した回数到達したときにブレークポイントが有効になる <br/>(`3`を指定すると`3, 6, 9, ...`回目に到達した場合のみブレークポイントが有効)|
|`Caller filters:` |特定のクラスやメソッドから呼ばれた場合のみブレークポイントが有効(もしくは無効)になる<br/>指定の仕方に癖があるので注意(例えば`*foo*`と指定すれば、`foo`を含むクラスやメソッドからの呼び出し時のみ有効/無効になる<br/> [詳しくはjetbrainsのヘルプページを参照](https://www.jetbrains.com/help/idea/using-breakpoints.html)|
|`Disable until breakpoint is hit:` : |ブレークポイントに依存関係を設定出来る。依存先のブレークポイントに到達するまでは自身のブレークポイントは無効だが、依存先のブレークポイントに到達したあとは自身のブレークポイントが有効になる。|

## 何回処理が実行されたか知りたい

当然、ブレークポイントでsuspendもログ出力もさせないことが出来ます。
ただ、suspendもログ出力もしないブレークポイントに何の意味があるのでしょうか。

実は、DebuggerのConsoleタブ > Overheadの部分には、ブレークポイントを通過した回数とデバッグに掛かったオーバーヘッドが表示されています。(**実際の処理に何ms掛かったかを表示するわけではないので注意**)

<img width="918" alt="overhead.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/09d8a920-5f36-31e3-d1a7-53cebd900871.png">

つまり、ログ出力やsuspendしないブレークポイントも、「どこか分からないけど、何かの処理が沢山呼ばれてる...」時の調査に威力を発揮します。

## アプリ起動時の処理をデバッグする

アプリ起動時にクラッシュする場合、原因を突き止めるためにブレークポイントを張って止めたいけど「起動後にデバッガをアタッチしたら間に合わないよ！」とか「毎回`Debug`やりなおすの面倒！」ってなりますよね。
もしくは「バックグラウンドでプロセスがKILLされた後の復帰時にデバッガをアタッチしておきたい」という場合。

そんなときは、デバッガをアタッチするまでアプリが起動しないようにしてしまいましょう。

### 手順

1. Android端末側の「設定」 > 開発者向けオプション > デバッグアプリを選択 > デバッグ対象のアプリを選択する
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/11e9e979-1367-ce44-5e35-fafa006eee5f.png">

1. Android端末側の「設定」 > 開発者向けオプション > デバッガを待機をONにする
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/5fc1a764-835c-cf0b-c0cd-98fc195553c6.png">

1. デバッグ対象のアプリを起動(普通にランチャーから起動するだけ)

1. 以下のような状態で止まるので、Android Studio側で該当アプリにデバッガをアタッチする
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/5325412c-9a85-b79e-0ec0-68df6fd246c8.png">

1. アプリ起動時点でデバッガがアタッチされた状態になる！！
<img width="585" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145534/6b6a3e90-6164-3fdc-e55c-2ec83b167c72.png">



こうすることで、`MainActivity#onCreate`も確実にブレークポイントで止める事ができます。

## まとめ

* ブレークポイントはただ処理を中断するだけではない
* ブレークポイントを上手く使えば、デバッグのための再ビルド回数が削減出来る(開発が早くなる！)
* ブレークポイントを上手く使えば、`Resume Program`の連打が不要になる(腱鞘炎にならない！)


現場からは以上です。

明日は @ysat さんの【ActiveRecordを使いつつDBのデータをメモ化して扱ってみる】です。
お楽しみに！！