ひつじのにっき

mhidakaのにっきです。たまに長文、気が向いたとき更新。

【AN-1】高性能なAndroidアプリを作るには - ティム ブレイ

高性能とは処理が早くて応答性の高いアプリのこと。

  • ANRやイベントループの停止を防ぐ技術
  • ボトルネックとなるI/Oアクセスについて
  • アプリケーションのパフォーマンス最適化手法

について解説。Androidの今後の予定についてもQ&Aで答えます。

関連ページ

AsyncTask

(追記)TechBoosterに解説記事を載せました(via @kacchi0516)
TechBooster Asynctaskを使って非同期処理を行う

IntentService

TraceView

EclipseのMemory Analyzer、MAT(http://www.eclipse.org/mat/)の使い方
Android アプリケーションのヒープメモリを観察する

(追記) TwitterID:pakuqi さんのブログです
Memory Analyzerの使い方

ユーザの満足度

高性能なAndroidアプリについて技術的なプレゼンテーションを行いたい。
総じてスピードの速いアプリケーションのほうがユーザエクスペリエンスが良い。
ただし、ウェブページの取得、データベースのアップデートは早いとはいえないだろう。
その時にユーザの不満をそらすには?何かヒントがある?
満足度を向上させる方法を伝えたい。
"推定はしないこと、なぜ遅いのかを測定する","ユーザへの敬意を"

Janky

ChromeチームによるJankという単語が作られた。
ユーザがスムーズさを感じないときを指し示す。
"A janky app"(おっそいアプリ、ストレスを感じる動作を意味する)

UIスレッドが大事

Androidのスレッド処理はマルチスレッド化されている。その中でも特別なのがUIスレッド。
描画、ユーザレスポンスに直結するUIスレッドではアプリケーションのロジック作業を行わないことが原則。
原則を守ることが満足度を高める第一義

ANRは世界最悪だ。もっともよくない。
アプリは追放(アンインストール)されてしまう。
5秒応答がない、インテントレシーバの処理に10秒かかる、
これらANRを引き起こす症状は起きてはいけないこと。
(ANR:Application Not Responding、アプリケーションが無応答状態になること)

マルチメディア処理、たとえばビデオを60FPSで再生している場合などは16msしか余裕がない。
一般に100〜200ms以上の遅延はJankyとなる。

ストレージ読込(1バイト)読み込み 25ms
ストレージ書込(1バイト)書き込み 200ms
サーバーへのPing(※) 100ms

(その他もろもろ…)
※信号強度、ホップの回数など様々な要素がかかる。
特にネットワーク経由でデータを取得する際は最低でも1秒かかってユーザエクスペリエンスが低下する

フラッシュへの書き込みについて(Yaffs2)

Flashは磁気ディスクとは違なった特徴を持つ。経過年数、書かれているデータ、デバイス種類などが影響してアクセス速度が変わってしまう。

ストレージへの操作(読み書き、権限付与など)はUIスレッドで行わないこと。
SQLiteはほかのデータベースと比べると小さいが、複雑な処理をおこなっていることに変わりはない。
リレーショナルデータベースを扱うときは注意して、慎重に考えること。やはりUIスレッドを使わないこと
たくさんのログはSQLiteをつかわず、プレーンのテキストを使うことを推奨する。
データ特性に合わせて記録形態を変えるのが大切だ。

I/Oは非常に遅い

ネットワークは遅いし、ストレージも遅い。
このようなレスポンスに時間がかかる遅い処理はUIスレッドで行わないように。

asyncTask

asyncTaskを使うことでI/Oの処理をUIスレッドより切り離せる。
進捗をプログレスバーを出すなどUIスレッドで描画は行うが、実際の書込処理などはバックグラウンドのスレッドで処理する。
(非同期タスクサンプルコード:http://developer.android.com/intl/ja/reference/android/os/AsyncTask.html)

Fire And Forget Modeと呼んでいる。
ファイア・アンド・フォーゲットとは撃ちっぱなしを指す軍事用語。処理が始まれば、(バックグラウンドで行うので)気にしなくて良い、ということ。

asyncTaskの詳細

いくつか注意点

  • UIスレッドから呼び出すこと
  • 再帰呼び出しはできない
  • Activityがbackgroundになってしまったときに処理中であってもasyncTaskを殺される可能性がある


解決策
android.app.IntentServiceを利用すること
呼び出されたら、Androidはアプリを生き残らせようとがんばる。

UIスレッドで遅い処理を行わないようにする便利なルーチーンがある。

ユーザの満足度向上のために

  • 全ボタンをDisableにかえてユーザ操作を禁止する
  • スピナーをつかい処理中を見せる(Androidではいろんな見せ方があるが、一つの提案として)
  • 200nを超えるようならプログレスバーを使う
  • AsyncTaskを利用する

アプリでの実装例

Android Marketに LifeSaver というアプリがある
Androidでは、電話の履歴、テキストメッセージの履歴が端末間を移動できない。
→これらデータをSD Cardに移動するアプリ
ユーザが何が行われているか、目で確認できるようにしている。
SDカードへのデータ移動は速くすることができないので、丁寧にユーザーに説明する。

パフォーマンスアドバイス

どうやって高速化するか。ボトルネットを見極めることは非常に難しい。開発者は事前の最適化は出来ないと肝に銘じるべき。
事前にやっておけば、もしかしたら早くなるかもしれない。が(全く変わらない可能性もあるので)あまりよい手法ではない。

重要なことは

  • 出来るだけシンプルな処理にする
  • テストして性能を確認 →問題なければおしまいだ。飲みに行こう。
  • 推定はしないこと、なぜ遅いのかを測定すること
  • 運が良ければ少しの修正で治るかもしれない

→通常、これらを何度か繰り返す必要がある。

プロファイリングツール

最適化を支援するツールの紹介

  • TraceViewを使う
  • Log.dでタイムスタンプを入れる
  • エクスストリームプロファイル(※)

※とてもパフォーマンスが気になる場合、ユーザーにAndroidAppを使ってもらい、フィードバックを得る。

TraceViewの使い方


android.os.Debug.startMethodTracing(String traceName)
android.os.Debug.stopMethodTracing()
http://developer.android.com/intl/ja/reference/android/os/Debug.html

3つ、遅くなるかもしれないところがある。

  • データ読込
  • データ保存
  • StringをJSONへ変換するなどCPUパワーに由来する箇所

TraceViewをつかって突き止めよう。Traceコードが入ると、スピードはおそくなる。

(デモの後、解析結果を図示してみせる)

TraceViewで実行すると、ほとんどprintに時間がかかっているのが分かる。
これはSDカードへの書き込みが考えられる。さらに細かくみていくとprintlnの読み出し、
そのうちの半分ぐらいがnewlineにかかる部分だ。
一方、このプログラムの30パーセントがJSONオブジェクトをStringに変換する作業で時間を消費しているようだ。
つまりプログラムを動かしている時間の3分の1はJSONオブジェクトをストリングへのコンバートしているだけだ。
→ 今回の場合は、頻繁に使うアプリではないのであまり気にしない。
見つけたボトルネックに対して最適化が必要であれば行うべきだ。

まとめ

  • 1つ目:ユーザへ敬意を払うこと。そのためにはユーザに最も近いUIスレッドは特に注意する。決して大きな作業をUIスレッドでやらないこと。

AsyncTask、IntentServiceを使う

  • 2つ目:推測をせずに測定を行うこと。測定ツールを使わない理由はない(=必ずやること)。クリス プルエットもTraceViewと何週間も共に過ごしたと言っていた。それほどに重要。

別のメモリアナライザ(MATがOOM調査するのに便利)も使える
Memory Analyzer http://www.eclipse.org/mat/
http://subtech.g.hatena.ne.jp/cho45/20100206/1265431649

最後に

ユーザーに敬意を、UIスレッドを大切に、何かを変える前に測定を。

Q&A

Q:Android 3.0でセキュリティは強化される?
A:次のバージョンを3.0と呼ぶかも決まってはいないが、セキュリティグループがAndroid開発チームの中には存在している。
Anroidでのセキュリティには非常に多くの労力が払われていると回答

Q:様々なAndroid端末が出てくるが開発者が対応する上で注意すべき点は?
A:Googleでは"互換性の問題"と呼んでいる。Android Developers blogで互換性の問題に関して一連の記事が書かれている
http://android-developers.blogspot.com/ 是非ともみていただきたい。
きちんとアプリケーションを書いて適切に対応すれば、Galaxy Tabのように1024*600といった解像度であっても
問題なく動作する(1000本以上のアプリケーションがきちんと動いた、とのこと)

(追記)
Q:C2DMはスケールするのか?
A:"We're Google!"