コンテキストを取得するためのさまざまなメソッドの違いは何ですか?


390

私が見てきたさまざまなAndroidコード:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

ただし、どれが適切で、どのような状況で使用すべきかについての適切な説明はありません。

これに関するドキュメンテーションへのポインタと、間違ったものが選択された場合に何が壊れるかについてのガイダンスは、大いに評価されます。


2
このリンクはあなたを助けるかもしれません。通過します。この ...
アージュ

回答:


305

Androidのコンテキストに関してはドキュメントが少ないことに同意しますが、さまざまなソースからいくつかの事実をまとめることができます。

GoogleのAndroid開発者の公式ブログに関するこのブログ投稿は、主にメモリリークに対処するために作成されましたが、コンテキストに関するいくつかの優れた情報も提供しています。

通常のAndroidアプリケーションでは、通常、アクティビティとアプリケーションの2種類のコンテキストがあります。

この記事をもう少し読むと、この2つの違いとActivity.getApplicationContext()、Activityコンテキストを使用するのではなく、アプリケーションContext()の使用を検討する必要がある場合について説明されていますthis。基本的に、アプリケーションコンテキストはアプリケーションに関連付けられており、アプリのライフサイクル全体を通じて常に同じです。アクティビティコンテキストはアクティビティに関連付けられており、画面の向きの変更中にアクティビティが破棄されると、何度も破棄される可能性があります。そのような。

Android SDKに取り組んでいるGoogleエンジニアの1人であるDianne Hackbornからの投稿以外に、getBaseContext()をいつ使用するかについて、本当に何も見つかりませんでした。

getBaseContext()を使用せず、手持ちのコンテキストを使用してください。

これはandroid-developersニュースグループの投稿からのものです。Androidで作業している少数の人々が実際にニュースグループを監視して質問に回答するため、そこで質問することも検討してください。

したがって、全体的には、可能な場合はグローバルアプリケーションコンテキストを使用することをお勧めします。


13
アクティビティBを開始でき、次にCLEAR_TOPフラグでAを再起動できる(そしてこのサイクルを何度も繰り返すことができる)アクティビティAがある場合-巨大なトレイルの構築を回避するために、この場合はどのコンテキストを使用する必要がありますか参照されるコンテキスト?DianaはgetBaseContextではなく 'this'を使用すると言っていますが、ほとんどの場合Aは再利用されますが、Aの新しいオブジェクトが作成されてから古いAがリークする状況があります。したがって、ほとんどの場合、getBaseContextが最も適切な選択のようです。その後、その理由は明らかではありませんDon't use getBaseContext()。誰かがこれを明確にできますか?
JBM 2011年

2
Activityを拡張しないクラス内のコンテキストオブジェクトにどのようにアクセスしますか?
Cole

1
@Cole、ここで「ExampleClass」と呼ぶクラスを作成できます。そのコンストラクタはContextオブジェクトを受け取り、クラスインスタンス変数「appContext」をインスタンス化します。次に、Activityクラス(またはそのほかのクラス)は、ExampleClassの「appContext」インスタンス変数を使用するExampleClassメソッドを呼び出すことができます。
Archie1986

54

これは私がの使用に関して見つけたものですcontext

1)。Activityそれ自体の中で、thisレイアウトとメニューの拡張、コンテキストメニューの登録、ウィジェットのインスタンス化、他のアクティビティの開始、Intent内での新規作成Activity、設定のインスタンス化、またはで利用可能な他のメソッドに使用しますActivity

膨張レイアウト:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

膨張メニュー:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    this.getMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
}

コンテキストメニューの登録:

this.registerForContextMenu(myView);

ウィジェットをインスタンス化:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

を開始Activity

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

設定をインスタンス化:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

2)。アプリケーション全体のクラスの場合getApplicationContext()、このコンテキストはアプリケーションの存続期間中存在するため、使用します。

現在のAndroidパッケージの名前を取得します。

public class MyApplication extends Application {    
    public static String getPackageName() {
        String packageName = null;
        try {
            PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
            packageName = mPackageInfo.packageName;
        } catch (NameNotFoundException e) {
            // Log error here.
        }
        return packageName;
    }
}

アプリケーション全体のクラスをバインドします。

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

3)。リスナーおよびその他のタイプのAndroidクラス(ContentObserverなど)の場合は、次のようなコンテキスト置換を使用します。

mContext = this;    // Example 1
mContext = context; // Example 2

ここthisまたはcontextクラス(活動、等)の文脈です。

Activity コンテキスト置換:

public class MyActivity extends Activity {
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        mContext = this;
    }
}

リスナーコンテキストの置換:

public class MyLocationListener implements LocationListener {
    private Context mContext;
    public MyLocationListener(Context context) {
        mContext = context;
    }
}

ContentObserver コンテキスト置換:

public class MyContentObserver extends ContentObserver {
    private Context mContext;
    public MyContentObserver(Handler handler, Context context) {
        super(handler);
        mContext = context;
    }
}

4)。以下のためにBroadcastReceiver(インライン化/埋め込まれた受信機を含む)、受信機自身のコンテキストを使用します。

外部BroadcastReceiver

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            sendReceiverAction(context, true);
        }
        private static void sendReceiverAction(Context context, boolean state) {
            Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
            mIntent.putExtra("extra", state);
            context.sendBroadcast(mIntent, null);
        }
    }
}

インライン/埋め込みBroadcastReceiver

public class MyActivity extends Activity {
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
            if (connected) {
                // Do something.
            }
        }
    };
}

5)。サービスの場合、サービス自体のコンテキストを使用します。

public class MyService extends Service {
    private BroadcastReceiver mBroadcastReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    private void registerReceiver() {
        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        this.mBroadcastReceiver = new MyBroadcastReceiver();
        this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
    } 
}

6)。トーストには通常getApplicationContext()、を使用しますが、可能な場合は、アクティビティ、サービスなどから渡されたコンテキストを使用します。

アプリケーションのコンテキストを使用:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

ソースから渡されたコンテキストを使用:

public static void showLongToast(Context context, String message) {
    if (context != null && message != null) {
        Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        mToast.show();
    }
}

そして最後に、getBaseContext()Androidのフレームワーク開発者のアドバイスに従って使用しないでください。

更新:Context使用例を追加します。


1
mContextの代わりに使用できますOuterClass.thisstackoverflow.com/questions/9605459/…の
Paul Verest

3
そのような役立つ答えの+1!受け入れられた回答は受け入れられた回答として問題ないことに同意しますが、聖なるモリーこの回答は非常に有益でした!これらの例をすべてありがとう、それらは私が全体としてコンテキストの使用法をよりよく理解するのに役立ちました。私はあなたの答えをリファレンスとして私のマシンのテキストファイルにコピーしました。
ライアン

13

私は数日前にこのスレッドを読み、同じ質問をしました。これを読んだ後の私の決定は簡単でした。常にapplicationContextを使用してください。

しかし、これで問題が発生しました。数時間かけて見つけ、数秒で解決しました...(1つの単語を変更...)

LayoutInflaterを使用して、Spinnerを含むビューを膨らませています。

したがって、2つの可能性があります。

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

次に、私はこのようなことをしています:

    // managing views part
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
    String[] myStringArray = new String[] {"sweet","love"};

    // managing adapter part
    // The context used here don't have any importance -- both work.
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    theParentView.addView(view);

私が気づいたこと:linearLayoutをapplicationContextでインスタンス化した場合、アクティビティのスピナーをクリックすると、ダルビック仮想マシンから(コードからではなく)キャッチされない例外が発生します。私の間違いがどこにあるかを見つけるための時間の......)

baseContextを使用する場合は、それで問題ありません。コンテキストメニューが開き、選択肢の中から選択できます。

だからここに私の結論があります:アクティビティでcontextMenuを処理するときにbaseContextが必要である(私はそれをさらにテストしていません)と思います...

テストはAPI 8でコーディングされており、HTC Desire、android 2.3.3でテストされています。

私のコメントがこれまであなたを飽きさせなかったことを願っています。幸せなコーディング;-)


アクティビティでビューを作成するときは常に「this」を使用しました。アクティビティが再開すると、ビューが再作成され、ビューを再度作成するために使用する新しいコンテキストが存在する可能性があることに基づきます。開発者のブログに投稿されている欠点は、ImageViewが破棄されている間、使用されるドローアブル/ビットマップがそのコンテキストにハングアップする可能性があることです。それでも、今はそうしています。アプリの他の場所(通常のクラス)のコードについては、アクティビティやUI要素に固有ではないため、アプリケーションコンテキストを使用します。
JonWillis 2012

6

まず、可能な限りappcontextを使用することに同意します。次に、活動中の「これ」。私はベースコンテキストの必要がありませんでした。

私のテストでは、ほとんどの場合、それらを交換できます。ほとんどの場合、コンテキストを取得する理由は、ファイル、設定、データベースなどにアクセスするためです。これらのデータは、最終的にはアプリのプライベートデータフォルダー(/ data / data /)内のファイルとして反映されます。使用するコンテキストに関係なく、それらは同じフォルダー/ファイルにマップされるため、問題ありません。

それは私が観察したものです。おそらく、それらを区別する必要がある場合があります。


起動時にアプリの言語をグローバルに設定するためにbasecontextが必要でした(電話のデフォルトの言語と一致しない場合)。
ティナ

3

場合によっては、スレッドで何かを実行するときに、アプリケーションコンテキストよりもアクティビティコンテキストを使用することがあります。スレッドが実行を完了し、結果を呼び出し元のアクティビティに返す必要がある場合は、ハンドラーを持つそのコンテキストが必要です。

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

2

簡単な言葉で

getApplicationContext()メソッド名が示すように、アプリのどこからでもアクセスできるアプリケーション全体の詳細をアプリに認識させます。したがって、これをサービスバインディングで使用できApplication contextます。ブロードキャスト登録などは、アプリが終了するまで有効です。

getActivity()またはthis、によって提供されるアプリレベルの詳細も表示される現在の画面をアプリに認識させapplication contextます。つまり、現在の画面について知りたいことは何でもWindow ActionBar Fragementmanger、このコンテキストで利用できます。基本的に、Activity拡張しContextます。このコンテキストは、現在のコンポーネント(アクティビティ)が有効になるまで有効です


1

混乱は、(表面上)識別可能な違いなしで、コンテキストにアクセスするための多くの方法があるという事実から生じます。以下は、アクティビティのコンテキストにアクセスできる最も一般的な4つの方法です。

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

コンテキストとは何ですか? 私は個人的に、コンテキストをいつでもアプリケーションの状態と考えるのが好きです。アプリケーションコンテキストは、アプリケーションのグローバルまたは基本構成を表し、アクティビティまたはサービスはその上に構築でき、アプリケーションの構成インスタンスまたはアプリケーションの推移状態を表します。

android.content.Contextのソースを見ると、Contextが抽象クラスであり、クラスに関するコメントが次のようになっていることがわかります。

アプリケーション環境に関するグローバル情報へのインターフェース。これは、Androidシステムによって実装が提供される抽象クラスです。これは、application-specificリソースやクラスへのアクセスを可能にするだけでなく、application-level起動アクティビティ、ブロードキャストおよびインテントの受信などの操作のアップコールも可能にします。私がこれから取り除いているのは、コンテキストがアプリケーションレベルとシステムレベルにアクセスするための共通の実装を提供していることです。リソース。アプリケーションレベルのリソースは文字列リソース[getResources()]やアセット[getAssets()]などにアクセスしている可能性があり、システムレベルのリソースはアクセスに使用するものですContext.getSystemService().

実際のところ、メソッドに関するコメントを見てください。それらはこの概念を強化しているようです。

getSystemService()system-levelサービスのハンドルを名前で返します。返されるオブジェクトのクラスは、要求された名前によって異なります。 getResources():アプリケーションのパッケージのResourcesインスタンスを返します。 getAssets():アプリケーションのパッケージのResourcesインスタンスを返します。Context抽象クラスでは、上記のすべてのメソッドが抽象であることを指摘する価値があるかもしれません!getSystemService(Class)の1つのインスタンスのみが実装を持ち、それが抽象メソッドを呼び出します。つまり、これらの実装は、主に以下を含む実装クラスによって提供される必要があります。

ContextWrapper
Application
Activity
Service
IntentService

APIドキュメントを見ると、クラスの階層は次のようになります。

環境

| — ContextWrapper

| — —アプリケーション

| — — ContextThemeWrapper

| — — — —アクティビティ

| — —サービス

| — — — IntentService

それContext自体は洞察を提供していないことがわかっているので、ツリーを下に移動してを見てみると、ContextWrapperそこにもあまりないことがわかります。Applicationは拡張ContextWrapperされるため、によって提供される実装をオーバーライドしないので、そこを見る必要はあまりありませんContextWrapper。つまり、コンテキストの実装はOSによって提供され、からは隠されていAPIます。ContextImplクラスのソースを確認することで、Contextの具体的な実装を確認できます。


0

私はこれとgetBaseContextonClick(JavaとAndroidの両方に非常に緑のnoobから)トーストするときにのみ使用しました。私のクリッカーが直接アクティビティにありgetBaseContext、匿名の内部クリッカーで使用する必要がある場合、これを使用します。私はそれがかなりトリックであると思いますgetBaseContext、それはおそらく内部クラスが隠しているアクティビティのコンテキストを返すことです。


1
これは間違っています。アクティビティ自体の基本コンテキストを返しています。匿名の内部クラスからアクティビティ(コンテキストとして使用するもの)を取得するには、のようなものを使用しますMyActivity.this。説明どおりにベースコンテキストを使用しても問題は発生しませんが、それは誤りです。
nickmartens1980 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.