AndroidではJavaでプログラムを書きますが、ふつうのコンピューターと比べればリソースの少ない環境ですので、特に気をつけてプログラミングする必要があります。
通常のJavaとも共通すること
定数はstatic final
にする
まず、final
にしなければ、変更可能になってしまうので定数になりません1。そして、一般に定数はインスタンスを問わず一定ですが、static
にしなければインスタンスごとに生成される無駄が発生してしまいます。さらに、public static final
な定数は、他のクラスから呼び出した場合も埋め込まれて効率的に処理できることがあります。
ラッパーオブジェクトに注意する
Javaでは、int
やdouble
といった型はクラスでない基本型ですが、それらをオブジェクトとして扱えるようにするために、Integer
やDouble
などの型があります。Java 5からは、自動で基本型とラッパーオブジェクトを変換してくれるようになりました(オートボクシング/アンボクシング)。
それはいいのですが、ラッパーオブジェクトはイミュータブルなので、これを使って計算すると「アンボクシング→演算→ボクシング」という過程を経てしまうので、無駄にラッパーオブジェクトの生成が続くこととなります。ジェネリクスの引数など、どうしてもObject
として扱いたい場面でだけラッパーオブジェクトを使って、一般的なコードでは基本型の数値を使いましょう。
ループで回すような文字列生成にはStringBuilder
を使う
JavaではString
もイミュータブルなので、文字列連結を+
演算子で行った時には、「その都度新たなStringBuilder
オブジェクトを生成して、それを使って連結を行い、結果のString
オブジェクトを得る」処理が走っています。もちろんこれは必要なことなのですが、ループで継ぎ足して文字列を生成し続けると、ループ1回ごとにStringBuilder
とString
が生成してしまって非効率になります。
そのような場合には、明示的にStringBuilder
を宣言して、連結する文字列を.append()
していって、最後にtoString()
として文字列を得ましょう。もっとも、1行内で済むような文字列連結であれば、わざわざ出すほどのことでもありません。
Androidの場合、特に注意が必要な点
ガベージコレクタ
ふつうのパソコン向けのプログラムを書く場合、大きなメモリを使う場面以外ではそれほどガベージコレクタを意識する必要はありませんが、Androidの場合は、絶対的な性能・メモリの使用可能量がパソコンより低いため、すぐにメモリは少なくなり、より負荷になるガベージコレクタが走るようになるので、意識する必要があります。
なお、LogCatにもGCの進行状況が出るので、様子を見ることができます。
大原則
基本的に、Java上で一度確保したメモリを解放できるのはGCだけなので、一時的でも何でもいったん生成したオブジェクトはGCに「解放してもらう」しか手段がありません。また、System.gc()
という関数があって、ガベージコレクタの動作を促す(動き出す保証はありませんが)ことは一応できます。ただし、解放すべきものがなくてもガベージコレクションは負荷のかかる操作であって、そしてシステム側でもメモリ不足のとき、アイドル時間などに適宜行なっているので、プログラムのメインループで定期的に呼び出すようなことはしてはいけません。初期化の完了時、動作モードが大きく切り替わるときなど、不要オブジェクトが多数発生する場面かつ、ユーザーがガベージコレクションによる待ち時間を負担視しないような場面であれば、有効かもしれません。
具体策
ガベージコレクタに負荷をかけないようにするには、「必要ないオブジェクトを生成しないようにする」のがいちばんの方法です。ループ内や画面書き換えごとなど、頻繁にオブジェクトを使う場合、むしろそれをフィールドに持たせるなどして再利用したほうが、毎回生成してはガベージコレクタに投げなくて済むようになるので、負荷が減るかもしれません。
-
final
にしても、配列やミュータブルなオブジェクトでは中身を書き換えられてしまいますが、とりあえずその問題は置いておきます。 ↩