重い腰をあげてLoaderを使ってみた(とりあえずinitLoaderだけ)

重い腰をあげてLoader触ってみました。

これまでもAsyncTaskはやめろ、Loader(AsyncTaskLoader)使えっていう話は知ってはいたんですが、Loader使い方よく分からんって敬遠してたんですよね。

とりあえずAsyncTaskLoaderを使ってみてわかったこと、感じたことを書いてみたいと思います。

参考にしたところ

サンプルはGitHubに上げてます。

未だによく分かってないところもあるんですが(キャンセル処理についてはまだ手を付けていない)、とりあえず現状で分かったことを書いてまとめます。

ちなみにソースコード読んで動きを把握したいなら、サポートパッケージではなくandroid.app.LoaderManager、android.content.Loaderを使った方がいいと思います。

LoaderManagerの動きを知る

getLoaderManager.initLoaderを呼ぶより前に、LoaderManager.enableDebugLogging(true);を実行すると、LoaderManagerがログを出力してくれるようになるので便利。

LoaderManagerがLoaderの状態を管理しているので、ActivityやAsyncTaskLoaderは非同期処理がどんな状態にあるのか気にしなくて済むのがいいですね。

ただしちゃんと動くようにするためには、Loder側でどういう状態の時にどのメソッドが呼び出されるのかを理解しておく必要があります。そのためにはLoaderManagerの動きを知っておかないとわけが分からないというわけです。

ついでに言うと、メソッド名から想定したイメージと実際の動きの間が、私の感覚と違っていて余計に混乱したというのもあります。

getLoaderManager().initLoader

getLoaderManager(もしくはgetSupportLoaderManager).initLoaderは指定したIDのLoaderがなければLoaderを作成、既に存在していればActivityへのCallbackを設定します。

Loaderを初期化するメソッドというより、コールバックを更新するものと思った方が理解しやすい気がします。私はずっとこのメソッドでLoader作って非同期処理を開始するものだとばかり思っていて、ずっと混乱していました。

指定されたIDのLoaderがまだ存在しない場合は、ActivityのonCreateLoaderにコールバックを行い、ここでLoaderを作ります。

Loaderを作るのはActivityのお仕事です。initLoaderだけなら、onCreateLoaderが呼ばれるのはActivityがonCreateされたとき(画面回転時は除く)だけです。

Loader.onReset

名前からして再稼働させた時に呼ばれるのかと思って混乱しました。いまだによく分かっていません。

onResetが呼ばれたLoaderは再利用されることはない・・・であってると思うんですけど、自信がありません。

LoaderManagerは、LoaderのIDごとに現在動いているLoader、以前に使ってたLoaderを管理しているだけなのようです。だから以前使ったLoaderのインスタンスを再活用したりはしてないと思います。

Loaderで使ってたリソースを解放してねってタイミングのようです。

バックグラウンド処理を引き継げる

とりあえずやってみて感じたのは、AsyncTaskと違ってバックグラウンドの処理を引き継げることがいいなと感じました。

AsyncTaskだと画面回転したらまた最初からやり直しになってたものが、そのままバックグラウンド処理は続いてくれるし、結果もそのまま受け取れるのが素敵。

Loader側でキャッシュ機構を持たせることで、ムダな非同期処理を防ぐことができるのもいいなと思います。

Loader側が非同期処理だけに専念できる

AsyncTaskと違って呼び出し元のActivity(Fragment)が生きてるかどうかを確認しなくていいのが想像以上にやりやすいです。

AsyncTaskだとonPostExecuteで処理結果をUIに反映します。バックグラウンド処理をしている最中に画面回転が生じるとUI更新しようとするものの、対象のActivityは既にお亡くなりになっているせいでアプリが落ちてました。

LoaderではUIの更新について何1つ考える必要がないので、とてもスッキリします。

でも途中経過を伝えられない

AsyncTaskLoaderには途中経過を通知するメソッドが標準で用意されていません。そのためバックグラウンド処理の途中経過を表示することができません。同じAsyncTaskがつくのに別物と

Read full post gblog_arrow_right

Android StudioでQuick Documentationを活用する

Android Studioでコーディングしていて、「このメソッドどういう処理するんだっけ?」と思った時に便利なQUICK DOCUMENTATIONがあります。

F1押すと出てきますが、標準だとFloating Modeで表示されて邪魔です(設定によって違うかもしれませんけど)。

Floatingモードで表示されて邪魔

これは右上の歯車マークをクリックして、Floating Modeを押して解除してやれば他の枠に収まってくれます。

Floating Modeを解除

私の場合毎回右側にDocumentationが収まるのですが、右側は個人的に見づらい。このDocumentationはドラッグすることで表示位置を移動することができます。

個人的には右下に置いておくのが好みです。

表示位置は調整可能

こうすることでQuick Documentation機能がぐっと使いやすくなります。

これでめでたしめでたしなんですが、このままではDocumentationの表示位置は現在開いているプロジェクト固有の設定にしかなりません。

つまり、別のプロジェクトを作成してQuick Documentationを利用した時に、再びFloating Modeで開かれてしまいます。プロジェクトごとに毎回この設定をするのは面倒なので、これを標準のレイアウトとして設定してしまいましょう。

方法はAndroid StudioのWindowメニュー→Store Current Layout as Defaultを選べばOKです。

標準のレイアウト設定にしてしまう

これで毎回設定せずともすみます。

Android Wearアプリを開発するときはversionCodeなどを一元管理すると便利

Android Wearアプリ(WatchFaceも)をGoogle Playで公開するときにbuild.gradleの共通化をやっておいた方がいいと思います。

Android Wearアプリプロジェクトを作成すると、標準ではmobileモジュールとwearモジュールが作成され、それぞれのモジュールにbuild.gradleが作成されます。

Google Playにアプリを公開する場合、build.gradleで指定するversionCodeとversionNameはmobile,wearモジュールで共通にしなければなりません。

初回アップロード時は両方同じ値なので問題ありませんが、アプリをバージョンアップする際に2つのファイルをいじらないといけないのは面倒くさいと思います。(というか絶対に忘れる)

そのためversionCodeなどは、一箇所直せばmobileとwearのどちらにも適用されるようにしてやるといいと思います。

私はmobile,wearのbuild.gradleで共通して利用する部分を、別ファイルにして読み込ませるようにしてみました。

QiitaのAndroidの署名情報(signingConfigs)を外出しようを参考にさせていただきました。

/mobile/buildConfig.gradle

defaultConfig {

    applicationId "jp.gcreate.product.customphotowatch"
    minSdkVersion 18

    targetSdkVersion 21
    versionCode 3
    versionName "1.0.2"
}

/mobile/build.gradle


apply plugin: "com.android.application"



android {

    apply from: "configBuild.gradle", to: android

    compileSdkVersion 21

    buildToolsVersion "21.1.2"

}

〜dependenciesは省略

/wear/build.gradle

apply plugin: "com.android.application"




android {

    apply from: "../mobile/configBuild.gradle", to: android

    compileSdkVersion 21

    buildToolsVersion "21.1.2"
    defaultConfig{
    
    minSdkVersion 20
    
}

}

〜dependenciesは省略

上記では省略しましたが、buildTypeも外部ファイルに出して両者で同じ設定が適用されるようにしてます。

やってて未だに不安なのが、ちゃんと正しく設定できているのか、確認の仕方がいまいち分からず不安だということでしょうか・・・。

先日のDroidKaigiで発表のあった、つかえるGradleプロジェクトの作り方のやり方も参考になります。

こちらのスライドでの方法は、versionCode等の値を/build.gradleで定義し、各々のプロジェクトその値を参照することで共通化するやり方です。

こちらのやり方のほうが分かりやすいなぁって発表聞いてて思いました。

ちなみにAndroid Studioではルートのことをプロジェクト、mobileとかwearのことをモジュールと呼びますが、Gradleの世界ではどれもプロジェクトと呼ぶそうです。勉強になりました。

Android Wearでwearとスマホ間でデータをやりとりする話

2019/05/18追記: この記事の情報は古いので公式ドキュメントを参照してください。


データのやりとりはWearable.DataApiを使うことでやりとりできます。Wearable.MessageApiを使うことでもできます。

両者の違いはこんな感じ。

DataApi

  • 接続が切れていても送信できる
  • データはonDataChangedで受け取る
  • 送れるデータは100KBまでだが、Assetを使うことで大きいデータも送れる
  • データを送信するというより、DataItemを更新して、その更新を通知するイメージ

MessageApi

  • 現在接続中のノードに対してデータを送信することができる
  • データはonMessageReceivedで受け取る
  • データを送る際にはノードを指定する必要がある

ノードIDについて

当たり前ですが、ノードIDはAndroid Wear端末とスマホで異なります。

WatchFaceを作成して、その設定画面を用意している場合、WearのノードIDはスマホ側では簡単に取得できます。

mobile側の設定画面となるActivityでgetIntent().getStringExtra(WatchFaceCompanion.EXTRA_PEER_ID)とするとWearのノードIDが取得できます。これは設定画面の起動がAndroid Wearアプリ経由で行われるためです。

一方Wearから、もしくはmobileからでもAndroid Wearアプリを経由しない起動の仕方をするアプリの場合はこの方法では取得できません。

その場合はNodeApi.getConnectedNodesを使うことで、接続されている端末のノードリストを取得することができます。現状スマホとAndroid Wearは1:1でペアリングされるはずなので、これで相手方のノードIDを取得できるでしょう。(将来的に複数ペアリングできるようになったらどうやればいいんでしょうね?)

DataApiを使ったデータ送信の注意点

[DataApi – Android Developers]のConcurrencyにありますが、DataApiを使ったからといってmobileとwearでDataItemが全く同じになるわけではありません。

onDataChanged()内であれば正しいデータが参照できます。これは変更があったDataItemが通知されてきているからです。

しかしAndroid Wear端末を再起動した後に、DataApiを使って送信された設定データを読み込もうとした時に問題が生じます。

wear側からDataItemを識別するUriでデータを取りに行っても、mobile側の設定と齟齬が生じている可能性があります。

その理由はDataItemが以下のように識別されているからです。

wear://ノードID/パス

mobileで作ったDataItemはmobileのノードIDで識別されます。同じパス文字列で識別しているからといって、勝手にwearのノードIDのものが変更されるわけではありません。

これはWatchFaceのサンプルコード(com.example.android.wearable.watchface)を見ると何となく分かると思います。サンプルコードでは、mobileからのDataItemの変更を受け取ると、wear側で同じデータを上書きする処理を行っています。

サンプルのようにmobileからもwearからもデータを送り合うようなアプリの場合、どちらのノードのDataItemも常に同じ状態にするように配慮しないと齟齬が生じて困ることになると思います。

片側からしか送らないというのであれば、ノードIDを指定してDataItemを取りに行くのもありかもしれません。

DroidKaigiに参加してきました

DroidKaigiに行ってきました。飛行機使って前泊での参加です。

満員でしたね。熱気がすごい。

今日ほど分身の術が使えたらと思うことはなかったでしょう。それくらい、全部のセッション聞きたかったです。

今後のアプリ開発に役立つ情報がいっぱいでした。現状動いてはいるけど、ちゃんとできてなかったところとか、「そうなんだ」っていう気付きもあって有意義でした。

とりあえず面倒臭がらずに少しずつテストを書くことから始めようかなと思います。

テストを動かす環境づくりがよくわからないとか、テストの書き方がよく分からないとか、個人でやってると仕様の変更で対応してしまってテストまで書き換える必要が出てきて面倒くさいとかで敬遠してたんですけど、つべこべ言わずにテスト書こうと思いました。

一方で、周りの空気に飲まれて受け身になりすぎたのが反省点です。なんかもうちょっと攻めの姿勢で聞けたら良かったのにと、振り返って思います。

質問とかできたら良かったんですけど、頭働かなくてそれどころではありませんでした。

言い訳ですけど、参加してる間はそれどころではなかったんですよね・・・。周りスゲーし、人はいっぱいだし、席の確保も大変だし、スケジュールは過密だしで話を聞くのが精一杯でした。

幸い皆さんスライドを公開してくださっている上に、スライド見るだけでも話の内容がある程度分かるようになってるので、後でじっくり復習したいと思います。

個人でアプリ作ってると、こういった周りの開発者さんたちの空気感とか全くわからないので、参加してよかったなと思います。わざわざ岡山から出張った甲斐はあったかな・・・。

運営の皆さん、発表者の皆さん、参加者の皆さん、お疲れ様でした。

Master of Fragmentの更新を首を長くして待ってます。

UndoBarを使った削除処理を考える

UndoBar – GitHub

削除処理を行って、それを取り消し可能なようにする実装を考えます。例えばGmailのアプリでメッセージをアーカイブしたときなどに表示されるあれです。

削除する際に「本当に消しますか?」みたいな確認ダイアログを表示するのはナンセンスっぽいです。

なぜならその確認ダイアログは、データが消えてアクセスできなくなるという責任をユーザーに転嫁してるだけだということです。そもそも削除したいだけなのにいちいち確認されるのもうっとおしいだけではないかという理由もあります。

それならば、もし消したくないデータを誤って削除してしまったとしても、それを復元できるようにするのがユーザー目線でいいだろって話です。

この辺りの話はSmashing Android UI レスポンシブUIとデザインパターンという本で知りました。

では実際に取消可能な削除機能を実装するためにはどうすればいいかというと、UndoBarを利用するのが簡単そうな気がします。Crouton使おうかと思ったけども、いざ使おうと思ったらレイアウトを実装したりするのが~~面倒~~大変だったので、シンプルなUndoBarを使いました。ソースコードはCroutonの方が読みやすかったけど。

UndoBarの表示

今回私がやりたかったのは、データベースに保存してあるデータを消すという例です。データベースに保存されているデータをListViewで表示している。そのListViewのうちの1つのアイテムを選んで削除をするというパターン。

実装方法としては削除の操作を行った時(UndoBarを表示させる時点)でどうするかによって、2パターンに分岐するかと思います。

  1. この時点で実際にDB上のデータを消してしまう
  2. この時点ではDBは触らず、見た目上のデータを消す
どちらのパターンにせよ、この時点でListViewに表示されてるデータを消すのは共通です。データベースのデータを消すタイミングがここかどうかです。

1.のパターンは見た目と実装がそのままリンクしています。Listから消えたらデータベースからも消える、シンプルです。

このパターンの場合は操作の取消を選んだら、消したデータを復元する必要があります。そのためどうやってデータをロールバックするのかに頭を悩ませることになります。データベースの構造が複雑だと元に戻すのが大変かもしれません。

2.の場合はUndoといいつつ、実際には削除処理を猶予しているだけです。このパターンの場合、取消操作はデータベースからデータを削除するのを取り消す処理(ややこしい)になります。

こちらは復元処理を考える必要がありません。一方でUndoBarが消える前にアプリを終了したり、画面が回転したときどうすんのっていう新たな問題が生じます。

UndoBarからのコールバック

UndoBarController.AdvancedUndoListenerを使うことで3つのタイミングによるコールバックを受け取ることができます。

この3つのコールバックをうまいこと利用して削除機能を実装していくことになります。

onUndo()

取消ボタンを押した際に呼ばれます。Undo時の処理をここで行うと良いです。

パターン1のときならここで復元処理を行うことになります。

onHide()

取消ボタンが押されず、UndoBarが消える際に呼ばれます。UndoBarに設定した表示時間が経過した後でコールされるわけです。UndoBar表示中に画面回転した場合には呼ばれません。

ちなみに画面回転に対応するには、自分でハンドリングしてやらないといけないそうです。今回私はそこまで踏み込みませんでした。

onClear()

UndoBar.clear()を明示的にコールした際に呼ばれます。

Read full post gblog_arrow_right

カスタムフォトウォッチ

カスタムフォトウォッチ

Android Wearを使っていて、背景画像を自分の好きな画像に設定したいと思ったことはないでしょうか。そんな人にちょうどいいのがこのカスタムフォトウォッチです。

作成のきっかけはデフォルトで設定できるウォッチフェイスの中に、日付と曜日を表示するものがなかったことでした。下にスワイプすれば日付は表示されますが、曜日は出ないしいちいちスワイプするのも面倒くさいので、盤面に常に表示してあるのがほしいなと思ったのです。

今のところデジタル時計だけですが、アナログ形式は要望が多ければ追加するかもしれません。(個人的にアナログは見づらいので優先度低めです)

以下の説明はすべてVer1.0.1のものです。

インストールの仕方

アプリはGoogle Playにて公開中です。

Get it on Google Play

カスタムフォトウォッチを使うためには、Android Wear端末とGoogleのAndroid Wearアプリが別途必要です。どちらが欠けていてもカスタムフォトウォッチは利用できません。

カスタムフォトウォッチをスマホにインストールすると、ペアリングしているAndroid Wear端末にも自動的にカスタムフォトウォッチがインストールされます。(この際、インストールにしばらく時間がかかります)

Android Wear端末にもインストールが完了すると、スマホのAndroid Wearアプリを起動すればウォッチフェイスの中にカスタムフォトウォッチが追加されます。Android Wear端末でウォッチフェイスの変更からカスタムフォトウォッチを設定できますが、基本的な設定はスマホから行います。

カスタムフォトウォッチをウォッチフェイスに設定すると、カスタムフォトウォッチのアイコンに歯車マークが出ます。再度タップするとカスタムフォトウォッチの設定画面が起動します。

ウォッチフェイスの選択画面

ウォッチフェイスの選択画面

カスタムフォトウォッチの設定画面を開くと、最初にこの画面が表示されます。

ここでは壁紙の追加と、既に追加した壁紙への切り替えが行えます。

右下の+ボタンを押すと次の画像の編集画面に移行します。

追加済みの画像を単にタップすると、ウォッチフェイスの設定(時刻の表示設定)に移行します。長押しするとポップアップメニューが開き、ウォッチフェイスの設定画面を経ることなく画像の切り替えのみを行ったり、不要になった画像の削除ができます。

画像の編集画面

画像の編集

この画面で実際にAndroid Wear端末に転送する画像を作成します。

左下のアイコンを押すことで、スマホ内に保存されている画像を読み込むことができます。SDカードやGoogleドライブにある画像を指定可能です。

カメラのアイコンを押せばその場で写真の撮影を行い、その画像を読み込むこともできます。

Android Wearに表示されるのは中心の明るい部分です。範囲外の部分は切り取られます。

画面内に表示した画像はスワイプすることで移動が、二本指でピンチイン・アウトすることによって縮小・拡大ができますので、Android Wearに表示させたい部分が中心になるように調整してください。

枠は四角と円形の切り替えが可能です。フレーム枠の変更は右上にあるアイコンをタップすることで行えます。(メニューからでも可)

ちなみに枠はあくまで表示確認のためのものであり、枠を円形にしたとしても画像は四角で切り抜かれます。あくまで円形ディスプレイのAndroid Wear端末でどのように表示されるか確認するためのものだとお考えください。

枠の切り替えボタンの隣は、周りの半透明の部分を黒色で塗りつぶすボタンです。Android Wear端末に表示される部分が明確になるので、実際に表示されるとどう見えるのか確認したいときにお使いください。もう一度タップすれば元の半透明に戻ります。

表示位置が決まれば、右下のハサミのアイコンを押してください。画像が切り抜かれ、ウォッチフェイスの設定画面に移行します。

ウォッチフェイスの設定(時刻の表示設定)

ウォッチフェイスの設定

Read full post gblog_arrow_right

WatchFaceのサンプルを実行する

Android Wearでウォッチフェイスを自作するためには、Creating Watch Faces – Android Developersを見て勉強するといいです。

なんかややこしそうな気がするかもしれませんが、そこまで複雑でもないです。Traningにも書いてありますが、Android StudioでWatch Faceのサンプルを取り込んでやると、どういうことやればいいのかわかると思います。

取り込み方はAndroid StudioのFileメニューからImport Samplesを選び、Wearable > Watch Faceを選択すればOKです。

Watch Faceサンプルを取り込む

サンプルの実行方法

このサンプルを実行する場合、実行環境にバツ印がついています。これはデフォルトで起動するActivityが設定されていないからです。

実行環境にバツ印がついている

そのまま実行しようとすると以下の様な警告メッセージが表示されますが、Continue Anywayを選べばAPKが端末へ転送されます。

気にせず続ける

毎回このメッセージが表示されるのはうっとおしいので、実行環境設定でDo not launch Activityを選んでおいた方がよいでしょう。

Activity起動設定

また、WatchFaceの設定画面を作るなど、デフォルトでは起動しないけど用意してあるActivityを起動したい場合は、「launch」を選んで起動させたいActivityを選んでおくと捗ると思います。(そうしないと、APKの転送→Android Wearアプリの起動→該当のWatchFaceを選択→設定画面を起動という手順を踏む必要があって面倒くさい)

ただ、この手法で起動するとgetIntent().getStringExtra(WatchFaceCompanion.EXTRA_PEER_ID);で、ペアリングしている端末のPeerIdを取得しようとしてもnullになってしまうので、PeerId依存の処理が上手くいかないことに注意しましょう。

WatchFaceの動作確認

アプリ(WatchFace)をどうやって端末に転送するのかというと、mobile(サンプルではApplication)とwearモジュールを両方とも実行(デバッグ)してやります。

そうすればWatch Faceが端末に送信されるので、後はスマホもしくはWear端末からWatch Faceの変更をしてやれば動作確認できます。

デバッグ実行はwearとmobile片方ずつやらないといけない

リリース用の署名をつけたAPKファイルであれば、mobile側の実行(端末へのインストール)さえ行えば、wear用のAPKがペアリングしている端末へ自動的にインストールされます。(mobile側のAPKの中にwear用のAPKが埋め込まれています)

しかしdebug用のAPKはこの自動転送が働かないので、wear用のAPKはwear用のモジュールを選んで実行しないと端末にインストールされません。

開発にあたっては、スマホ側とWear側両方実行しないといけないので若干面倒くさいです。

サンプルで使われているLog.d()について

サンプルでは様々なタイミングでLogにメッセージを流すようになっていますが、そのままではこれを確認することができません。

というのもLogを出力する前にisLoggableでログの出力レベルを設定を確認しているためです。

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onConnected: " + connectionHint);
        }

これをLogcatで確認するためには、実行する端末に対してadb shell setprop log.tag.(TAGで指定されている文字列) DEBUGとターミナルから入力してやると、端末のLogcatにログが出力されるようになります。

Android Studioでソースコードを読むのに覚えておくと便利なショートカット

最近になってようやくサンプルなどのソースコードを読むようになったのですが、「あ、こんな便利な機能あったのね」というのを紹介します。

ショートカットキーはMacのものを書いてます。メニューにショートカットキーも表示してくれているので、Windowsの方はそこで調べてください。

Find Usages

調べたい変数やメソッドにカーソルを合わせてOpt+F7

Edit > Find > Find Usages

変数やメソッドがどこでどう使われているか調べるのに使います。今まで右クリック→Find Usagesで表示させてました。もしくはIdeaVim使っているので「/文字列」で検索してました。

メンバ変数(フィールド変数)だとValue readでどこで参照されているかが、Value writeでどこで変更されているかが表示されます。

フィールド変数でFind Usages

メソッドだと、どこで呼ばれているかが表示されます。

メソッドでFind Usages

プライベートフィールドに対して特に効果を発揮する機能です。

ちなみにFind Usagesで使われ方を表示した後は、Cmd+Shift+↓(↑)で次に出てくるところに飛んでくれます。さらにいうとCmdとOptを押し間違えると、表示させてる行の位置が入れ替わったりするので注意してくださいね。

戻る

Cmd+[

Navigate > Back

日本語キーボードだと[ではなく@になります。

Find Usagesなどを使ってジャンプした場合に、ジャンプ前に読んでた場所に戻ってくれます。今まで「前読んでたところどこだ・・・」とイライラしながら探してました。

戻りすぎたらCmd+](日本語キーボードなら[)で1つ先へ飛びます。

この機能を使わずしてソースコードは読めない。

とりあえずこの2つの存在を知っているだけで格段にソースコードを読む辛さが緩和されます。

Declaration

Cmd+b もしくはCmd押しながらクリック

Navigate > Declaration

私はDeclarationの意味をよく分かってないのですが、宣言先に飛ぶってことなんだと思います。

親クラスで定義されてるメソッドを呼んでる時に、そのソースコードに飛ぶときに使ってます。例えば何気なく使ってるfindViewById()はいったい何やってんだって調べたりする感じです。Cmdキー押しながらクリックするだけなんで、ショートカットキー覚えてなくても行けそうな気はします。

Android Support Libraryのクラスだとソースコードまで付属してないのでそのままでは見れないんですけどね(見れないわけではないようです)。

Android標準のクラスならソースコードもインストールしてあれば確認することができます。Android SDK ManagerでSources for Android SDKをインストールしておく必要がありますが、開発する上ではないと困ると思うのでインストールしておいた方がいいでしょう。

SDK ManagerでSources for Android SDKをインストールしておく

Javadoc表示

Javadocを確認したいメソッド等にカーソルを合わせてF1Shift+F1でブラウザで見れます)

Read full post gblog_arrow_right

Androidアプリを開発する上で賢いLogの出力方法(とその確認の仕方)

今までずっとLog.d("test",”デバッグメッセージだよ”);みたいな感じでLogを出力し、Logcatで確認しながらプログラミングしていたのですが、とあるサンプルを見ていた時にこんなコードに出くわしました。

    private static final String TAG = "DigitalWatchFaceConfig";

        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onConnected: " + connectionHint);
        }

プログラムを実行しても、このログはlogcatに出力されません。

「なんでだ?」と思って調べているうちに、この方法はAndroidアプリ開発していく上で賢い選択なのだなということが分かってきました。

ベストプラクティスなのかどうかまでは分かりませんが、少なくともいきなりLog.d()で出力したり、アプリ内でprivate boolean isDebug = true;みたいにしてデバッグログを出力させるよりは賢いなと思いました。

参考サイト

[Log.isLoggable – API Refference](https://developer.android.com/reference/android/util/Log.html#isLoggable(java.lang.String, int))

ログレベルを制御する – TechBooster

ログの出力はアプリのパフォーマンスを下げる

ログの出力はアプリのパフォーマンスに影響します。少なくともStringオブジェクトを作ってそれを出力するわけですからね。

リリース時にはLog出力する部分を全部削除するのが一番いいのでしょうが、さすがにそれは手間が大きすぎます。それにリリースしたからといって開発が終わるわけでもなく、メンテのためにまた1からLogを出力するように直すのはあまりにも馬鹿らしいです。

Logを使わず開発するのはそもそも無理です。

Log.isLoggableによるチェック

Log.isLoggableによるチェックは、端末に設定されているログ出力レベルを判定しています。デフォルトでは全てのタグについてINFOが設定されています。

つまり最初のコードのようなLog.DEBUGでチェックをかけるとfalseが返ってくるのでログが出力されません。

ログ出力レベルの変更

ではどうやってログが出力されるようにすればいいのかというと、ターミナルでadb shell setpropコマンドを使います。

adb shell stop
adb shell setprop log.tag.設定したいタグ名 ログレベル
adb shell start

最初の例のログを出力させようと思ったらadb shell setprop log.tag.DigitalWatchFaceService DEBUGとターミナルから打ち込んでやればOKです。(ちなみにadb shellで端末にログインしてからであれば、いきなりsetpropから初めてOKです)

ログ出力レベルの確認

タグごとのログ出力レベルを確認するには、adb shell getprop log.tag.タグ名を使います。何も設定していない状態であれば空白が返って来ます。setpropで設定してやると、現在設定されているログ出力レベルが返って来ます。

Read full post gblog_arrow_right