世界中のいかなるパフォーマンステストをもクリア出来ながらも利用者を激怒させるようなコードを書くことは出来ます。 つまり、応答性の悪いものです。ノロノロ動いたり、ずいぶん長い間待たされてしまったり、あるいは入力処理に長時間かかってしまうものなどです。
Androidにおいては、システムは長時間応答しないアプリケーションをシステム側で検出し、ユーザに対してApplication Not Responding (ANR; アプリケーションが応答していません)ダイアログを表示します。ユーザはアプリケーションの処理を続行することも出来ますが、使うたびにこのダイアログが 出てくるアプリケーションを使い続けたいとは思わないでしょう。ANRが表示されることが無いよう、アプリケーションの設計において応答性を考慮することは大切です。
一般的にシステムはアプリケーションがユーザの入力に対して応答しない場合にANRを表示します。例えば、アプリケーションがI/O処理でブロックされている (ネットワークアクセスにおいてありがちです)場合、アプリケーションのメインスレッドはユーザ入力イベントを処理することが出来ません。一定時間後に システムはアプリケーションがハングアップしたと判定し、ANRを表示して終了出来るようにします。
同様に、アプリケーションがあまりにも長い時間、大規模なメモリ内構造の構築に時間をかけたり、あるいはゲームの 次の一手を考えるのに時間をかけすぎた場合にもシステムはアプリケーションがハングアップしたと判定します。 前述のテクニックを用いてこれらの処理を効率的に行うことは、常に重要なことですが、ぎりぎりまで チューンされたコードでもやはり時間がかかる場合はあります。
これらの場合、対応策は子スレッドを作成してそちらでほとんどの処理を行うことです。これにより メインスレッド(ユーザインターフェイスのイベントループを処理するもの)は走り続けることが出来るようになり、 システムからコードがフリーズしたと判定されることは無くなります。このようなスレッド化は通常 クラス単位で行われるものであるため、応答性はクラスについての問題であると認識する必要があります。 前述のような通常のパフォーマンス問題がメソッドレベルの問題のものである点と異なることに注意して下さい。
ユーザに表示されるANRダイアログ
本ドキュメントでは、Androidシステムがどのようにしてアプリケーションが応答していないと判定するかを解説し、 アプリケーションが応答性を保つためのガイドラインを提示します。
本ドキュメントで扱うトピックは以下の通りです。
Androidにおいて、アプリケーションの応答性はActivity ManagerとWindow Managerの両システムサービスによって監視されます。 Androidは以下の場合に、該当アプリケーションに対してANRダイアログを表示します。
上記のANR発生条件を知った上で、ANRがAndroidアプリケーションにおいてなぜ発生するのか、 そしてANRを回避するための方法を考えていきましょう。
Androidアプリケーションは通常、シングルスレッド(mainのみ)で動作します。 つまり、アプリケーションがメインスレッドで行う処理に時間がかかる場合、入力イベントやインテントの ブロードキャストに対して応答出来ず、ANRダイアログの表示につながる可能性があります。
つまり、メインスレッドで動作するメソッドはなるべく少ない処理しか行わないようにする必要があります。
特に、アクティビティはライフサイクル管理のためのキーとなるメソッド、onCreate()や
onResumeメソッド内での処理は極力抑える必要があります。
ネットワークやデータベース関連の処理など、長時間かかる可能性のある処理や
ビットマップのリサイズなど計算に時間のかかる処理などは越すレッドで行うべきです
(データベースアクセスについては、非同期リクエストを利用する方法もあるでしょう)。
しかしこれだけでメインスレッドが子スレッドの処理終了を待つためにThread.wait()や
Thread.sleep()を利用しては処理がブロックしてしまい、意味がありません。
子スレッド終了までのブロックを防ぐためには、メインスレッドは子スレッド処理完了時に呼び出される
Handlerを用意する必要があります。
この方法でアプリケーションを設計することで、メインスレッドは入力に対して応答性を保つことが出来、
"5秒入力放置"で表示されるANRダイアログを回避することが出来ます。
UI表示を行うスレッドでは同様のタイムアウト設定が為されるため、この方法はUI表示を行う
全てのスレッドにおいて使うべきものです。
IntentReceiverの実行時間に関する制約は、IntentReceiverの特性をよく表現しています。 つまり、「設定の保存や通知情報の設定/登録などの小さく、軽量の処理を行うためのもの」ということです。 このため、メインスレッドにて呼び出される他のメソッドと同様にアプリケーションは長時間かかりうる処理や 計算をBroadcastReceiver内で行うべきではありません。また、インテントのブロードキャストに対する 応答を行う必要がある場合、子スレッドを作成して処理を行う(これによってBroadcastReceiversを早く終了させる)よりも、 アプリケーションからServiceを開始することが望ましいと言えます。 余談ですがIntentReceiverからアクティビティを開始するのも、また避けるべきことです。このようなことを 行うと新たなスクリーンを生成し、ユーザが実行中のアプリケーションからフォーカスを奪うこととなってしまうためです。 アプリケーションがインテントのブロードキャストに対応してユーザに対する応答を表示する必要がある場合、 Notification Managerを利用するべきです。
一般に100~200ミリ秒以上の停止状態が発生するとユーザはアプリケーションの動作にもたつきを感じます。 そのため、以下ではANRを回避するだけでなくユーザにとっての気持ちよい応答を実現するためのtipsを紹介します。