Keeping Your App Responsiveを読んだ
http://developer.android.com/intl/ja/training/articles/perf-anr.html
上記を読んだ雑なメモ。
- システムはアプリケーションが一定以上の時間応答しないとANRダイアローグを出して、そのアプリケーションを閉じるかどうか尋ねて、ユーザーにアプリを閉じる選択肢を与える
- システムがANRを出さないように設計すべき
ANRが起こる条件
- UIスレッドでネットワーク通信やゲームの表示用オブジェクトの生成等をやるとx
- 時間がかかりそうな処理はUIスレッドで行わない
- ワーカースレッドを作ってそちらでほとんど行う
- これによって、UIスレッド(ユーザーインターフェースのイベントループ*1を動かしている)を稼動状態にして、システムを凍結させるのを防ぐ
このようなスレッド処理はクラス単位で行われる => 応答性はクラス単位の問題だと考えることが多い(普通はメソッド単位で考えるが)
Androidでは、アプリケーションの応答性はActivity ManagerとWindow Manager system servicesで監視されている。
- AndroidがANRを表示する条件は下記の2つの条件を検出したとき
- キータッチなどの入力イベントに対して5秒以内に反応がないとき
- BroadcastReceiverの処理が10秒以内に終らなかった時
ANRを避ける方法
- インプットイベントやインテントを受け取るチャンスをアプリにあげないようなコード(通常、何も指定しないとすべての処理をUIスレッドで行うが、そんなコード)
UIスレッドで動くメソッドは小さくしよう
- 特にActivityの
onCreate()
とonResume()
といったライフサイクルメソッドで行うセットアップ処理は可能な限り小さくしよう- いまはバックグラウンドで用意するための処理を呼び出し、みたいな感じだっけか
- 画像の整形やネットワーク/DBヘの接続はバックグラウンドで
- 特にActivityの
もっと効率的に長時間のワーカースレッドを作る方法は
AsyncTask
クラスの利用- 作った
AsyncTask
のクラスのジョブの実行は下記のような感じ。
new DownloadFilesTask().execute(url1, url2, url3);
- もっと複雑な場合は、自分自身のThreadクラスを作るか、
HandlerThread
クラスを利用する。 - そうする場合、あなたはスレッドの優先順位を
Process.setThreadPriority()
メソッドでセットし、THREAD_PRIORITY_BACKGROUND
の値を指定する必要がある。- そうしないとUIスレッドより優先してバックグラウンド処理が行われ、別スレッドに書いたのにANRが起こるとかある。
- ThreadやHandlerThreadクラスを実装するとき、それらの完了までUIスレッドをブロックしないようにする(=つまり、
Thread.wait()
やThread.sleep()
は呼ばない) - メインスレッドをブロックするかわりにメインスレッドはそれらのスレッドの完了時のpost backを受け取る
Hanlder
を提供する - メインスレッドでネットワークの処理等を書いてないかを調べるStrictモードがあるらしい
応答性を強化する
- ユーザーがあれ?と思うのは0.1~0.2s
- バックグラウンドジョブに時間がかかる場合ProgressBarなどで進捗を示す
- 計算はワーカースレッドで
- 初期化処理に時間がかかるならスプラッシュが面を入れてはどうでしょう
- SystraceやTraceviewといったパフォーマンスツールを使ってみよう
感想
- ANRの条件は知ってた
- なんだか、AsyncTaskの書き方に親しみが出てきた
- 余裕が出てきたら、SystraceやTraceviewといったパフォーマンスツールを使ってみたい
英語 | |
---|---|
sluggish | 動きののろい |
*1:ちょっと分かりきってない単語だ