Static Singleton vs. Application Subclass

シングルトンは自前の Static Singleton を実装すべきか、Application サブクラスを使うべきか?

Application のサブクラスを Singleton 的な目的で使うことはよくある話だが、実際に Static Singleton を使うのか、(Static Singleton の一種である)Application サブクラスを使うのかには、議論の余地があるようだ。

StackOverFlow の議論:Singletons vs. Application Context in Android? によると、Static Singleton 派と Application サブクラス派に分かれていて、両派ともほぼ対等な支持を得ている。

しかし、公式リファレンスには以下のようにある:

★ Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.

この記述を見る限り、どちらかというと、Singleton 的なことをしたいのであれば、単に Static Singleton を使う方がお勧めのようだ。global context を使いたいのであれば、Context.getApplicationContext() で得た Context オブジェクトを Singleton の getInstance() で引数として渡せば用が足るとしている。「Singleton 的なもので、さらに処理の中にグローバルコンテキストを扱うものが含まれるから Application を使う必要がある」と考えるのは誤解だということだ。Singleton の方がモジュール化された使い方ができるので、どちらかというとお勧めのようなニュアンス。

では、公式リファレンス的には、どういう場合に Application のサブクラスを使えばいいと考えているのだろうか? おそらく、Application に定義されたメソッド(onCreate, onLowMemory, onTerminate, onTrimMemory)等を活用したいというような場合だろう。Singleton 性は Application をサブクラス化する理由としては不要だということだ。加えて、Context をグローバル化する(ApplicationContext を使う)という観点からも、なら ApplicationContext を引数で Static Singleton に getInstance() 時に渡せばいいよね、Application をサブクラス化する必要性の理由にはならないよね、という訳である。

このように、公式リファレンスの記述から読み取れるメッセージは明らかに、「わざわざ Application をサブクラス化すな」である。

StackOverFlow の Application サブクラス派の回答者の主張は、「Application のサブクラスは、OS がしっかりとライフサイクルを管理しているから、自前の Static Singleton よりも《安心できる》」という、具体的な根拠の乏しい、精神衛生的観点についてのものである。しかし、このような恐れが杞憂であることは、公式リファレンスの記述からも明白であろう。保障されている(白か黒)かどうかわからないグレーゾーンの物事に対しては、このような戦略は有効だが、公式に黒であることが否定されている物事に対して、このような保障を託して安全策を取ろうとするのは過剰である。

ただし、アプリのプロセスが終了しないのに、Static オブジェクトがガベージコレクションされる場合があるという未確認の情報も報告されている(参考:AndroidにおけるSingletonパターンのベストプラクティス)。この話が正しい場合は、グレーゾーンなので、安全を取って Application サブクラスを使うというのもアリだろう。しかし、参考記事の筆者も、確認が取れていないという話だし、公式にもそういった情報がないわけで、さらに、他にそういった情報にも行き当たらない。基本的に、Application に限らず、Android では様々な API で Static Singleton が使われており、Static Singleton の安定性が揺がされるとすると、OS の安定性にも影響するわけである。なので、そのようなこと(アプリのプロセスが終了しないのに、Static オブジェクトがガベージコレクションされる場合がある)はないと思う。また、OS の安定性以上の安定性をアプリ側で追求することも虚しい努力だと思う。

ただ、それでも、《アプリのプロセスが終了しないのに、Static オブジェクトがガベージコレクションされる》ケースとして考えられるとしたら、Application コンテクストではなく、Activity コンテクストに紐づけられた Static オブジェクトの場合である。例えば、Activity の中に、private な static 変数として定義されたオブジェクトの場合、Activity クラス自体がガベージコレクションの対象となった場合に、クラス定義もろともアンロードされる可能性はある。default / protected についてはよくわからないが、public static に定義された Singleton であれば、Activity のアンロードに巻き込まれないのではないか。Android のソースを読んだりして深く検証するほどの余裕はないので、実際のところは確定できないが。

まあ、公式リファレンスの記述と考え合わせても、特に、ガチガチに守りを固めて Application サブクラスで行くというよりは、(Public) Static Singleton で行くのが妥当かなと思う。

そもそも Singleton を使う必要はあるのか

  • トップダウン的な物の見方をすると、(画面の回転等の)脆いライフサイクルで生滅を繰り返す Activity に Model データを置かないで、プロセス次元のライフサイクルを持つ Application サブクラスや Static Singleton に置けば、Activity の生滅に関する心配はしなくてよくなるんじゃね? ということになる。
  • 一方、ボトムアップ的な物の見方をすると、(onSaveInstanceState / onRestoreInstanceState で Bundle を使って退避する等して)Activity の生滅にも耐えるように作っておけば、Application サブクラスとか Static Singleton とか、余計なものを用意する必要はないじゃね? ということにもなる。

ライフサイクルの観点から言うと、基本的には後者に軍配が上がると思う。結局、プロセスが終了する(させられる)場合には、どこかで SharedPreferences を使うなどして Persistent なデータとして退避する必要がある。結局そのような Model データのライフサイクル管理をするのなら、Application サブクラスや Static Singleton よりも、Activity のライフサイクルの中でやってしまった方がいい。Model データがActivity のライフサイクルに耐えられるように作ってあれば、当然、プロセス(≒ Application)の終了にも耐えられるわけで、追加の対策が必要になってくるわけではない。

では、Singleton を使いたい場面はどういう場面かというと、シングルトン性が必要となる場合だろう。クレジットカードの申込フォーム内容とか、ショッピングカートの商品など、複数の Activity による処理で共有される Model データが、多重に発生してしまわないように、単一性を担保したい場合である。結果的に、処理が Activity をまたぐ段階でライフサイクルに巻き込まれることになるが、本来の目的は複数の Activity 間で共有されることによる単一性の担保であり、ライフサイクルを乗り越えることそのものが目的ではない。

つまり、前者(Singleton)は(時)空間な超越が主目的であり、後者は時間的な超越が主目的である。目的用途が異なっている。

空間性が問題にならず、単にライフサイクル、時間的な超越が目的であれば、Singleton の利用は考えなくともよい。

コメント

このブログの人気の投稿

EP-805A 廃インク吸収パッド交換

m3u8 ファイルをダウンロードして ffmpeg で MP4 に変換・結合

WZR-HP-AG300H with OpenWrt