ちりもつ on ytRino

Chirimotsu was born before Chiritsumo was.

Application Contextは使ってはいけない

タイトルは誇張です。

みんな大好きpotatotipsという勉強会で以下のようなトークがあったようです。(現場には行っていません)

曰く「ActivityContextで何千回もやったら数回リークが検出された。 なるべくApplicationContextを使おう」とのことらしいですが、間違いなく死人が出る(誇張)と思いますのでご注意ください。

(追記20160527: 修正されたようです なんかすみません) speakerdeck.com

結論

Application Contextは使わないでください。(誇張)

(実際は使うときは使う)

なぜApplication Contextなのか

Application Context使おうぜ!という根拠の記事としてこちらのフェンリルのDeveloper's Blogの [追記あり] Android 開発で気をつけたいこと 〜変数名と Context について〜 (フェンリル | デベロッパーズブログ) という2012年3月の記事が2年に1回ぐらい話題になると思います。

そしてこの根拠としてあげられるのが2009年1月のAndroid Developersのブログ Avoiding memory leaks | Android Developers Blog です。

たしかに最後のまとめには

・Try using the context-application instead of a context-activity
超訳) Application Contextを使おう!

とあり、いかにもApplication Contextが正解かのように見えないこともないです。

その詳細がその前段にあり、雑に訳すとこんな感じのことが書かれています。

Contextに関連したメモリリークを避ける簡単な方法が2つあって、1つはそのContextをそのスコープ外で使わないこと、もう1つはApplication Contextを使うこと。このContextはActivityのLifecycleに依存しない。長生きするオブジェクトでContextが必要なときはApplicationオブジェクト思い出せばおk

この2つは本質的には同じことを言っていて「スコープ考えて使おうか…」です。「Application Context最高! これ使っておけばメモリリークにサヨナラ!」とは言っていません。

ちなみに、上記フェンリルのブログの

Context の引数として以下のように Activity 自身を MainActivity.this のようにして渡しても、一見問題なく動作するのですが、メモリーリークをする危険性があります。 (参考 URL : http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html )
new Intent(MainActivity.this, FooActivity.class);

特に理由がない場合は、以下のように this ではなく getApplicationContext を使用する方が無難ですし、メモリリークが起きることを回避することができます。
new Intent(getApplication(), FooActivity.class);

に対しては以下のように明確に否定されています

ただ、これだけでは「じゃあやっぱりいつもスコープ広いApplication Contextでいいじゃん」と言えなくもないですが、そもそも「なんでApplication ContextとActivity Contextがあるのか」というのを考えてみましょう。





なぜActivity Contextなのか

考えましたか?
今ぱっと出てこずに考えたあなたはAndroid 2級です。Rxよりも先に学ぶべきことがあります。

というのは半分冗談です:bow:が、
具体的なApplication ContextとActivity Contextの違いについてはこちらの2012年2月の記事にものすごーくいい感じに実際の結果とともに書いてありますので御覧ください。 Yukiの枝折: Android:引数はthisか?getApplicationContextか?ActivityとApplicationの違い

つまるところActivityにはそれぞれのthemeなんかがあるので適当にやってると思った通りにならないことがあるどころか、上記記事のように最悪クラッシュします。
まあそれは動かしてみればすぐわかるので、大した問題では無いように思うえるかもしれませんが。

Contextの違いついて、もう少し長い、具体的なシチュエーションの説明がAndroid DevelopersのGoogle+のポストにあります。2012年3月の投稿です。

plus.google.com 雑に訳すと、

ViewをつくるのにApplication Contextを使うのが癖になってるなら、思った通りのものが出来上がらない、なんてことにぶち当たるまでそう長くはないだろう。でもApplication Contextダメだって言うなら何を使えばいいんだ? それはそのViewをどこに置くか次第だ。
 ActionBarにはgetThemedContext()があってaction barに適切なthemeがついたやつを使える。Theme.Holo.Light.DarkActionBarなんかはActivityのコンテンツ部分とは全く異なる見た目になる。
 Dialogにはdialog windowに必要なthemeが使えるgetContext()がある。AlertDialog.Builderを使ってるならViewのinflate時にはDialogオブジェクトはないだろうから、API11からgetContext()を追加した。
 他にはサブペインと他とで大きく異なる見た目にするのにもContextが使える。ContextThemeWrapperってのでContextをくるんでLayoutInflaterなんかに渡せばいい。
 これらを使い分ければ最高のアプリを作るのが楽になるはずだ。

(詳しくは原文をあたってください)

つまり、特にViewに関連するところでApplication Contextを使うのはアンチパターンです。(上記の例で言えばActivity Contextも適切でないパターンまで発展してますが)

あなたが AndroidManifest.xml<activity>に一度でもandroid:themeと書いたことがあるのであればApplication Contextを使うのをやめましょう。android:theme<application>にしか書いたことがない人も今のうちにやめたほうが良いでしょう。

結論

特に理由がないときはApplication ContextではなくActivity Contextを使いましょう