くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

Contextについて

今回はAndroidでよく出てくるContextについて説明しようかと思います。

ContextはAndroidでよく出てくると思うのですが、漠然としたものでフワフワしていたので、少し調べてみました。

Contextとは?

Contextを公式で確認すると下記のような記載があります。

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

Android OS の環境やリソースへのアクセスの窓口となるコンポーネントです。 データベースやファイル、アプリで利用する画像データなどへのアクセスの窓口となるほか、他のアプリとの連携や、アプリ情報へのアクセスの窓口ともなります。 よく使うのはリソース取得、Activityの起動、intentの送受信などかなあと思います。 また、Context はライフサイクルを持っていて、 端末の様々な 状態遷移の管理も、Contextが行います。

Contextはいくつかの種類が存在します。アプリを作る際には、 どの種類のContext かを意識する必要があります。

Contextの種類

  • Application:Android アプリ全体を統括します。 アプリケーションが起動してから終了するまでのライフサイクルを管理します。シングルトンなので、1つしかないです。
  • Activity:1つの画面を統括します。MVC モデルの、コントローラに相当する役割を担います。 1つの画面が構成され、バックグラウンドに移るか、終了するまでのライフサイクルを管理します。
  • Service:画面を持たず、バックグラウンドで動作します。 バックグラウンドで常に動き続ける常駐型の Service と、都度起動と終了をする Service の2種類があります。 Service が作られてから終了するまでのライフサイクルを管理します。

Contextの取得

Contextを取得することがよくあると思います。大まかには下記のようにして取得します。

  1. Activityのthis
  2. ActivityやApplicationのgetApplicationContext
  3. ViewやFragmentのgetContext

1は特になじみのある方が多いと思います。1はthis@MainActivityのようにすることもできます。

this@にするパターンは下記の例の場合です。

class A {
    inner class B {
        fun Int.foo() {
            val a = this@A
            val b = this@B

            val c = this
            val c1 = this@foo
        }
    }
}

上記の場合はthisはInt foo()のレシーバーであるIntになります。

なので、スコープ外にあるAやBを取得する場合にはthisをつけます。

ここで注目したいのはActivityでContextを取得する場合はthisgetApplicationContextの2つの方法があるということです。

どちらを使っても良さそうで、しかもgetApplicationContextはnullにならないので、ActivityでgetApplicationContextを使おうと思う方もいるかもしれません。

ただ、その場合は意図しない挙動になったり、下手したらメモリリークを引き起こす可能性もあるということを頭に入れておかないといけません。

まず、getApplicationContextの場合はAndroidManifest.xmlに設定したテーマが参照され、thisの場合はAndroidManifest.xmlのに設定したテーマが参照されるかという違いがあります。

そして、常にApplicationContextの方を参照してしまうと意図しないView(標準ダイアログなど)に割り当てられたり、メモリリークの原因となる可能性があります。

QA Stackというサイトに下記のパターン別取得方法が載っていたので、参考になるかもしれません。

f:id:kumaskun:20201108195620p:plain
パターン別Context取得推奨方法

この表をみると基本的にはライフサイクルに従うものはActivityで取得すべきなので、thisを使い、AlpplicationにまたがるものはgetApplicationContextがいい気がします。

例えば、AlertDialogは専用のクラスを作る場合が多いかもしれませんが、表示させるのはActivityでの画面の上なはずです。 そうすると、ライフサイクルに従った方が合理的な印象はあります。

ただ、この辺りは諸説いろいろあるため、いろんな意見を聞いてみたいです!!

自分はこうしているなどあればコメントしてくださると嬉しいです!!

参照

Kotlin リファレンス

getContext()、getApplicationContext()、getBaseContext()と“ this”の違い

Android:引数はthisか?getApplicationContextか?ActivityとApplicationの違い