【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と呼んでいる。
ファイア・アンド・フォーゲットとは撃ちっぱなしを指す軍事用語。処理が始まれば、(バックグラウンドで行うので)気にしなくて良い、ということ。
アプリでの実装例
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!"