読者です 読者をやめる 読者になる 読者になる

ちりもつ on ytRino

Chirimotsu was born before Chiritsumo was.

Application Contextは使ってはいけない

android

タイトルは誇張です。

みんな大好き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を使いましょう

Butterknife 7.0で@FindViewになるはずだった@InjectView、リリース直前で@Bindに変更される

android

f:id:ytRino:20150628153151p:plain README.md out of date · Issue #274 · JakeWharton/butterknife · GitHub

上記のやりとりがきっかけとなったのか、はたまたタイミングが重なっただけか、 長らくsnapshotだったButterknife 7.0.0が今日(6/28)リリースされていた。

で、この7.0にはResource Injection #140 (初版)という機能追加の他にもう一つ破壊的(?)な変更があった。

@FindView

github.com

長らく「これって"inject"じゃなくね…?」という話があるとか無いとかで、僕なんかの末端ユーザは「なるほど」という雑な感想しか持っていなかったのだけど、Jakeも気になっていたのかついに@InjectViewにとってかわり、新しく@FindViewというアノテーションがうまれた。Butterknife.inject()Butterknife.bind()になった。3月のことである。

それから3ヶ月、その間にGoogle I/Oで発表されたDataBindingなんかの話もJake的には「Butterknife、まだまだいけるっしょ」 (雑)というスタンスのようだ。が、リリースはされないままだった。

@Bind

で、ようやく最初の「今週末にリリースするよ」という言葉通りリリースされたわけだが…

( ゚д゚)ポカーン Bind...? てか8.0のプランが…?

f:id:ytRino:20150628152910p:plain

お分かり頂けただろうか…直前になって@Bindに変更されている

ハハッ

DataBindingの話にやはり思うところがあったのか、#bind()なんだから@Bindだろと思っただけなのかよくわからないが、 とにかく@InjectView@Bindになったのであった。

(ちなみに初版では@InjectStringなどだったリソース系は、実際にmergeされたときには@ResourceStringになり、同様に@BindStringに変更されてリリースされた)

以上、急に変更されてリリースされたのが面白かったというメモ書きでした。

ところでこちらは来ないんでしょうか Split the compiler and runtime into separate artifacts. by riotopsys · Pull Request #210 · JakeWharton/butterknife · GitHub

RxJavaでフィボナッチ

Java Rx

RxJavaでフィボナッチ数列を生成しようとしたけど面白くなかった - visible true

を見て自分でもやってみた。
(RxJava(というかRxAndroid)をさわっては見てるけどOperator多すぎて困る。)
はじめはscanとかで出来そうって思ったけどあんまりうまく行かないのでFn-1とFn-2のストリームをzipするとかいう大げさなものが出来上がった。
Fn-1とFn-2をSubjectとして、流れてきた値をFn-1 -> Fn-2, Fn -> Fn-1へと流す。
そうするとzipされて次のFnに流れてくる。

それぞれのストリームの流れもlogしてみると予想していたきれいなzipとは違ってるけどまあなんとなく動いているか、というところ。
なんかもっといい感じn(

Android書いてる間に書いていてretrolambdaもないのでJava8っぽさ0だ

RxFibonacci