システムに溶け込むために

データを失わないように

Androidは電話用のプラットフォームであることを常に頭に置いておいて下さい。ここで当然のことでありながら重要なのが、アプリケーション実行中に他のActivity(例えば、『着信中』といったアプリ)が前面に表示されることがあるということです。これによりonFreeze()とonPause()メソッドが実行され、アプリケーションが停止されます。

他のActivityが表示された際に、アプリケーションがkillされるとユーザがそれまで編集していたデータが失われてしまうことになります。このため、やりかけのデータを保存するのが最優先となります。『Android流』では、入力を受けたり編集を行ったりするアプリケーションは、onFreeze()メソッドをオーバーライドし、ユーザが再度アプリケーションを実行した際に元の状態に戻せるよう、アプリケーションの状態を何らかの形で保存することが必要とされます。[※1]

この動作の例として分かり易いのはメールアプリケーションでしょう。他のActivityが開始された際にユーザがメールを書いていた場合、アプリケーション側ではそのメールを下書きとして保存すべきです。 データが漏洩しないように

下着姿で街を歩きたくないのと同様に、データについても漏洩を避けなければなりません。ある種のアプリケーションはどこからでもアクセス出来るようにすることが可能ですが、[※2] 通常これは良いことではありません。生データを[※3] 他所から読み込めるようにすることは他のアプリケーションに対して独自データフォーマットの解釈を強要することになり、フォーマットが変わってしまった際にはその変化に追従しないアプリケーション全てを切り捨てることになってしまいます。

ここでの『Android流』は、他のアプリケーションに対してデータを公開するために洗練され、メンテナンス性の高いAPIを持ったContentProviderを作成することです。ContentProviderを用いることはJavaにおいて2つの密結合したコードをインターフェイスにより分割しコンポーネント化するようなものです。つまり、ContentProviderによるインターフェイスさえ維持すれば他のアプリケーションに影響を与えず、内部構造を好きに変更することが出来ます。

ユーザを邪魔しないように

ユーザ自身がアプリケーションを実行している場合、例えば電話中にPhoneアプリケーションを実行している場合などはユーザ自身が望んでそれを実行していると言うことが出来るでしょう。[※4] このため、前述のようにカレントActivityにおけるユーザからの入力に対する直接応答を除いてはActivityを自前実行すべきではないのです。

つまり、IntentReceiverや背後で走っているServiceからActivityを実行してはならないということです。これは現在実行されているアプリケーションに割り込むことになり、ユーザを苛立たせることになります。ひょっとすると更に悪いことに、新たに起動したActivityが前から走っていたActivityに対する入力データを横取りしてしまうことも考えられます。アプリケーションにおいて何をするかによりますが、いずれにしても良くない結果を導きかねません。

Activityをバックグラウンドから直接実行するのではなく、NotificationManagerを用いて通知アイコンの設定をすべきです。通知情報はステータスバーに表示され、これはユーザの気が向いた時にクリックすることが出来ます。

(但し、これは自身のActivityがフォアグラウンドで動作している場合には当てはまらないことに注意して下さい。この場合、ユーザは入力に対する素直な応答を求めているはずです。)

重い処理はスレッドで[※5]

アプリケーションがリソースを必要としたり時間のかかる計算を行ったりする場合には、処理をスレッドで行うのが良いでしょう。これにより『Application Not Responding(アプリケーションが応答しません)』ダイアログの表示を抑制出来、強制終了されることが無くなります。

デフォルトではActivity内のコードはViewに属するものも含め、単一のスレッドで実行されるようになっています。つまりActivity用の処理とUIイベント処理は同一スレッドで行われます。例えばユーザがキーを押すと、Activity内メインスレッドのキューにキーダウンイベントが追加されます。これをイベントハンドラ側で取り出し、速やかに処理出来なければ、システムはアプリケーションがハングアップしたと認識しユーザに対して強制終了のダイアログを表示することになります。

実行に時間のかかるコードをActivity内で実行するとイベントハンドラをブロックしてしまいます。これにより入力処理が遅れANRダイアログの表示につながります。これを避けるのには処理をスレッドで行うことが有効です。詳しくは『応答性が良いアプリケーション開発のために』をご参照下さい。

巨大なActivityを作らない

有用なアプリケーションには、いくつかの画面を持つものが多いでしょう[※6] 。UIを分割する際には、Activityを有効活用出来るように気をつける必要があります。

開発バックグラウンドによりますが、Activityを(同じアプリケーションのエントリポイントであるという点で)Java Appletのようなものと捉えられているかもしれませんが、この認識は正確ではありません。AppletはJava Appletにおける唯一のエントリポイントですが、Activityは潜在的にアプリケーションに対する複数のエントリポイントであると見ることが出来ます。メインActivityとそれ以外のものの違いはメインのものがAndroidManifest.xmlファイルにおいてandroid.intent.action.MAIN指定されているというだけです。

つまり、アプリケーションをActivityの集合と捉えるのがよいでしょう。それによりコードをメンテナンスし易くなり、また副次的な作用としてAndroidのアプリケーションヒストリやバックスタックモデルとの親和性が高まります。[※7]

テーマを拡張する

ユーザインターフェイスのLook & Feelにおいては、調和が大切です。ユーザは想定外のインターフェイスに出くわすと混乱してしまいます。そのため、UIを設計する際には独特の表現を極力避け、テーマを活用するのが良いでしょう。テーマには必要に応じて様々な拡張を施すことが出来ますが、それでもUI設計のスタートポイントは他のアプリケーションと同じ位置となるので、ユーザを混乱させることが少なくなるでしょう。詳細についてはアプリケーションにテーマを適用するをご参照下さい。

解像度に対して柔軟に

Androidデバイスでは、それぞれ解像度が異なることになるでしょう。ものによっては縦長モード・横長モードといった具合に解像度を動的に変更することが出来るようになるかもしれません。このため、アプリケーションのレイアウトや画面要素を柔軟に作っておく必要があります。

幸い、これはさほど難しくありません。UIを構築するページに詳細が書かれていますが、簡単に言ってしまえば代表的な解像度についてそれぞれ素材を用意し、様々な形に対応出来るレイアウトを行うということになります(すなわち、絶対位置指定を避け、相対位置指定を行うということになります)。これらに気をつけておけばあとはシステム側でうまくやってくれるので、どのようなデバイスでも良い見た目を提供することが出来るようになります。

ネットワークは遅い前提で

Androidデバイスは様々なネットワーク接続体系の上で走ることになります。全てのデバイスでデータアクセス機能が利用可能となるはずですが、速度はまちまちです。多くのデバイスはGSMネットワーク向けの低速なGPRS上で動作することになるでしょう。3G対応端末でさえ、非3G環境で使われることが多いでしょう。どのみち、当分の間低速ネットワークは使われ続けるということです。

そのため、アプリケーション開発においては常にネットワークアクセスと必要帯域幅を最小限に抑える必要があります。ネットワークが高速であることを前提としてはならず、常にネットワークアクセスが低速化した時のことを考えなければなりません。低速でもきちんと動作しつつ、ユーザが高速ネットワークにアクセス出来ればより良い体験を出来る、という形が理想的で、逆にユーザが高速ネットワークを使える時だけマトモに使えて、それ以外はろくに使えないアプリケーションではイライラしてしまうでしょう。

ここで注意して欲しいのは、エミュレータを用いた開発においてはデスクトップ環境のネットワークを利用できるため、実環境の状況を考えずにアプリケーションを書いてしまいがちであるということです。普通デスクトップ環境は携帯用ネットワークより高速で、エミュレータ設定を変更し低速ネットワークをシミュレートする必要があるかもしれません。この設定はEclipse上では『Emulator Settings』タブにて行うか、あるいはエミュレータの開始時コマンドラインオプションにて行うことが出来ます。

デバイスによってキーストロークは異なる

Androidでは様々なハンドセットのフォームファクタをサポートすることになるので、あるデバイスは”QWERTY”のフルキーボードを装備し、あるものは40キーであり、またあるものは12キー、あるいはもっと他のものが出てくるかもしれません。同様に、タッチスクリーンをサポートするものとしないものが出てくるでしょう。

アプリケーションを構築する際には、これを忘れないようにしなければなりません。本当に特定のデバイス群のみでの動作を前提とするのでなければ、特定のキーボードレイアウトを前提とすべきではありません。

バッテリを大切に

ワイヤレスデバイスは、壁のコンセントに指しっぱなしでは意味がありません。ハンドヘルドデバイスはバッテリ駆動であり、バッテリ寿命が長ければ長いほど嬉しいに決まっています。バッテリを消費する二大要因はプロセッサと電波であり、それゆえにアプリケーションを極力軽量化し、またネットワーク利用頻度を極力低減することが重要なのです。

アプリケーションが利用するプロセッサ時間を最小限に抑えるための方法は効率的なAndroid用コードを書くにはページを参照して下さい。電波利用による電力消費を抑えるためには、エラーを正しく処理することと本当に必要なデータしか取得しないことが重要です。例えば、ネットワーク処理が失敗した際に延々とリトライするのはよくありません。失敗の原因はユーザが電波の届かない場所に居るためかもしれず、その場合はすぐに再試行してもバッテリを浪費するだけであまり意味がありません。

ユーザは敏感なので、プログラムが多くの電力を消費するということは彼らに丸分かりで、そういったプログラムはすぐにアンインストールされてしまうでしょう。