- this(Activityクラスの中で)
- getApplicationContext()
クラスとしてはどちらも同じContextですが、インスタンスとしては全く別ものです。Application、Activityそれぞれがそれぞれ自身のContextインスタンスを保持しており、中身も当然異なります。同じContextクラスだからといって、これを意識せずに使うと例外エラーやメモリリークなどいろいろな不具合を引き起こすことになります。
Android APIの例で考えると、ToastクラスではToast.make()でContextを要求しますが、これはどちらのContextでも動作します。しかし、DatePickerDialogクラスではコンストラクタでContextを要求しますが、ActivityのContextを渡さないと動作しません。ApplicationのContextを渡すと例外エラーを引き起こします。Contextを要求するAPIを使う時はどのContextを使うべきか、まずドキュメントを確認するべきです。困ったことにAPIドキュメントにも明確にどのContextを使えと記載していない場合もありますが。
別の例で、ActivityのContextを参照するようなstatic変数を使ってしまった場合、Activityが終了するときに参照をきちんと削除しないと、参照が残っているのでContextを削除することができず、メモリリークが発生します。特にstaticなAndroidクラスを使う場合、知らないうちに内部でActivityのContextが参照されてしまい、一見わかりにくいケースもありますので、そのような場合は特に注意が必要です(参考にあるサイトを参照)。
とりあえず使い分けのキーワードは「ライフサイクル」です。ContextとそのContextを参照するオブジェクトのライフサイクルは同じであるべきで、片方のオブジェクトが削除されるときは、もう一方もきちんと削除されるように作るべきです。当たり前のように聞こえますが、うっかりミスなどで簡単にリークする上に、同じContextクラスなのでビルドエラーもでなく、メモリリークはわかりにくい、と実は細心の注意が必要です。
Activityのインスタンスは頻繁に生成と削除が行われます。画面の向きを変えただけでも発生します。逆にApplicationのインスタンスは基本的に永続します。それぞれのもつContextも同じライフサイクルになります。なので、どちらに属するべきかを考慮し、属した方のライフサイクルにあわせて作り込めばメモリリークのないアプリを作ることができます。なんでもかんでも永続させるとメモリリークはしなくてもメモリを大量に使用するアプリになるので、あくまでも適切なほうのライフサイクルであるべきです。
参考:Android DevelopersのBlog:Avoiding memory leaks
No comments:
Post a Comment