「Android ApplicationContext ActivityContext」でググればApplicationContextを使うべきからActivityContextを使うべきまで幅広い主張の記事がありますが、当記事ではActivityContextじゃなければいけないとき以外はApplicationContextを使おうという主張をしていきます
ApplicationContext派とActivityContext派の主張
どっちがいいのか論を語るうえでは双方の主張を見ていく必要がありますよね。ざっと軽く述べると以下のような感じではないでしょうか。
ApplicationContext派
- ActivityContextを使うとメモリリークを誘発させる
- ApplicationContextのほうが軽量
ActivityContext派
- Themeに関する情報はActivityContextが必要
- Viewの生成もThemeに関わるのでActivityContextが必要
- ActivityContextが必要なケースがある
どちらの主張も正しいのですが、自分はメモリリークのリスクに対してコスト(インスタンスの寿命を考えること)を払いたくないので、できるだけApplicationContextを使う派です。
ActivityContextを使う必要がある場面
できるだけApplicationContextを使いたいですが、ActivityContextが必要となるケースがあるのも事実です。ここはうまく使い分けるというのが重要となってきます。そのため、ActivityContextが必要な場面を把握しておく必要があります。
- Themeの情報が必要な時
- ActivityごとにThemeを設定できる
- DayNightやActivity側で多言語対応1してる場合とか
- Viewを生成する時
- ActivityにBroadcastReceiverを登録する場合
- ActivityのライフサイクルにBroadcastReceiverを合わすことができるみたい
- Dialogを生成する時
だいたいこんなところでしょうかね?(探せばもっとあると思いますけど)
ApplicationContextを使うと嬉しいこと
ActivityContextを使うということはActivityの参照を持つということです。それはActivityより長寿命で参照するとメモリリークしてしまうということです。Activityの寿命にContextの利用者側が合わせればいいだけですが、アプリの設計レベルでContextの利用者側を完全に把握しておく必要が出てきます。そういうのは面倒ですよね?面倒なのでできる限りApplicationContextに寄らせることで精神衛生を保とうという自分の主張です。
アーキテクチャーレベルでContextの使いどころを考える
MVPやMVVMなどでレイヤードアーキテクチャー的な設計をすると、ActivityContextが必要な場面はView層に集約できます(たぶん)
残りのレイヤーではActivityContextを使うまでのないことが残っていると思います。たとえば文字リソースの取得や、SharedPreferencesとかApplicationのFilePath取得とか。それらであるならばApplicationContextを利用することでメモリリークのリスクを考えなくていいユートピアを築けるでしょう。
メモリリークのリスクならアーキテクチャーレベルで軽減できる話
実はApplicationContextを使うことでメモリリークのリスクを軽減するのはおまじないレベルの対策であって、本来ならばアーキテクチャーレベルで考えなければなりません。
具体的には以下を徹底すればいいでしょう
- ApplicationクラスにActivityの参照を与えない
- staticにActivityの参照を保持しない
- retain instantなFragmentにActivityの参照を与えないか、与えるならActivityの寿命に参照を合わせる
ぶっちゃけ参照が途切れればGC対象になってメモリリークすることはないのですが、インスタンスがどのContextの参照を持っているかなんて考えたくないのでApplicationContextをなるべく使おうという話でした~
Footnotes
-
Contextの言語設定を動的に切り替えるのはGoogle的には辞めてほしさを感じますね ↩