web-dev-qa-db-ja.com

Androidで「コンテクスト」を取得するための静的な方法は?

静的メソッド内で現在のContextインスタンスを取得する方法はありますか?

私はそのように探しています。なぜなら私はそれが変わるたびに 'Context'インスタンスを保存するのが嫌だからです。

885
Andrea Baccega

これを行う:

Androidのマニフェストファイルで、次のように宣言します。

<application Android:name="com.xyz.MyApplication">

</application>

それからクラスを書いてください:

public class MyApplication extends Application {

    private static Context context;

    public void onCreate() {
        super.onCreate();
        MyApplication.context = getApplicationContext();
    }

    public static Context getAppContext() {
        return MyApplication.context;
    }
}

アプリケーションのコンテキストを静的に取得するために、どこでもMyApplication.getAppContext()を呼び出します。

1212
Rohit Ghatol

アプリケーションコンテキストを取得するための便利な方法を必要とするアプリの大多数は、 Android.app.Application を拡張する独自のクラスを作成します。

_ guide _

これを実現するには、まずプロジェクト内に次のようなクラスを作成します。

import Android.app.Application;
import Android.content.Context;

public class App extends Application {

    private static Application sApplication;

    public static Application getApplication() {
        return sApplication;
    }

    public static Context getContext() {
        return getApplication().getApplicationContext();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;
    }
}

次に、AndroidManifestのAndroidManifest.xmlのタグにクラスの名前を指定します。

<application 
    ...
    Android:name="com.example.App" >
    ...
</application>

次のようにして、任意の静的メソッドでアプリケーションコンテキストを取得できます。

public static void someMethod() {
    Context context = App.getContext();
}

_ warning _

上記のようなものをあなたのプロジェクトに追加する前に、ドキュメンテーションが何を言っているかを考えるべきです:

通常、Applicationをサブクラス化する必要はありません。ほとんどの場合、スタティックシングルトンはより機能的な方法で同じ機能を提供できます。シングルトンがグローバルコンテキストを必要とする場合(たとえば、ブロードキャストレシーバを登録する場合)、それを取得する関数には、シングルトンを最初に構築するときに内部的にContext.getApplicationContext()を使用するContextを指定できます。


_ reflection _

リフレクションを使用してアプリケーションコンテキストを取得するもう1つの方法もあります。反射はAndroidではよく見落とされており、私は個人的にこれをプロダクションで使用すべきではないと思います。

アプリケーションコンテキストを取得するには、API 1から使用可能になっている隠しクラス( ActivityThread )のメソッドを呼び出す必要があります。

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("Android.app.ActivityThread")
            .getMethod("currentApplication").invoke(null, (Object[]) null);
}

アプリケーションコンテキストを静的な方法で取得する方法を提供するもう1つの隠しクラス( AppGlobals )があります。これはActivityThreadを使用してコンテキストを取得するため、次のメソッドと上記で投稿されたメソッドの間に実際に違いはありません。

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("Android.app.AppGlobals")
            .getMethod("getInitialApplication").invoke(null, (Object[]) null);
} 

ハッピーコーディング!

69
Jared Rummler

いいえ、ありません。残念なことに、あなたはActivityまたはContextの他のサブクラスの1つからgetApplicationContext()を呼び出そうとしています。また、 this という質問は多少関係しています。

49
Erich Douglass

アプリケーションコンテキストを取得することについて話していると仮定して、私は@Rohit Ghatolがアプリケーションを拡張することによって示唆されるようにそれを実装しました。そこで起こったことは、そのような方法で検索されたコンテキストが常にnullではないという保証がないということです。あなたがそれを必要とするとき、それはあなたが時間内に遅れることができないのは通常あなたがヘルパーを初期化したい、またはリソースを得たいからです。ヌルケースを処理しても役に立ちません。だから私は docs で述べられているように、私は基本的にAndroidアーキテクチャと戦っていたことを理解した

注:通常、Applicationをサブクラス化する必要はありません。ほとんどの場合、静的なシングルトンはより機能的な方法で同じ機能を提供できます。シングルトンがグローバルコンテキストを必要とする場合(たとえば、ブロードキャストレシーバを登録する場合)、シングルトンのgetInstance()メソッドを呼び出すときに、Context引数としてContext.getApplicationContext()を含めます。

/によって説明された Dianne Hackborn

アプリケーションが派生できるものとして存在する唯一の理由は、1.0より前の開発の間、私たちのアプリケーション開発者の一人が、派生できるトップレベルのアプリケーションオブジェクトを持つ必要があるという絶え間ないバグを抱えていたためです。 「それらのアプリケーションモデルに、そして私は最終的に手放しました。私は永遠にそのモデルを手放すことを後悔します。 :)

彼女はまた、この問題に対する解決策を提案しています。

アプリのさまざまな部分で共有できるグローバルな状態が必要な場合は、シングルトンを使用します。 [...]そして、これはより自然にあなたがこれらのものを管理するべきであるということに導きます - それらをオンデマンドで初期化します。

それで、私は、Applicationを拡張することをやめ、プライベートコンストラクタの中でアプリケーションコンテキストへの参照を保存しながら、シングルトンヘルパーのgetInstance()に直接コンテキストを渡しました。

private static MyHelper instance;
private final Context mContext;    

private MyHelper(@NonNull Context context) {
    mContext = context.getApplicationContext();
}

public static MyHelper getInstance(@NonNull Context context) {
    synchronized(MyHelper.class) {
        if (instance == null) {
            instance = new MyHelper(context);
        }
        return instance;
    }
}

呼び出し元はローカルコンテキストをヘルパーに渡します。

Helper.getInstance(myCtx).doSomething();

したがって、この質問に正しく答えるには、アプリケーションコンテキストに静的にアクセスする方法がありますが、それらはすべてお勧めできません。ローカルコンテキストをシングルトンのgetInstance()に渡すことをお勧めします。


興味のある方は、 fwd blog でより詳細なバージョンを読むことができます。

45
Alessio

これは、UIスレッドのどこからでも Application (Contextである)を取得するための 文書化されていない の方法です。これは隠し静的メソッドActivityThread.currentApplication()に依存しています。少なくともAndroid 4.xでは動作するはずです。

try {
    final Class<?> activityThreadClass =
            Class.forName("Android.app.ActivityThread");
    final Method method = activityThreadClass.getMethod("currentApplication");
    return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
    // handle exception
} catch (final NoSuchMethodException e) {
    // handle exception
} catch (final IllegalArgumentException e) {
    // handle exception
} catch (final IllegalAccessException e) {
    // handle exception
} catch (final InvocationTargetException e) {
    // handle exception
}

このメソッドがnullを返す可能性があることに注意してください。 UIスレッドの外側でメソッドを呼び出す場合、またはアプリケーションがスレッドにバインドされていない場合。

アプリケーションコードを変更できるのであれば、 @RohitGhatol の解決策を使用することをお勧めします。

36
kennytm

それはあなたがコンテキストを使用しているものに依存します。私はその方法の少なくとも一つの欠点を考えることができます:

AlertDialog.BuilderAlertDialogを作成しようとしている場合、Applicationコンテキストは機能しません。現在のActivity...の文脈が必要だと思います。

32
gulchrider

RoboGuice を使いこなすのであれば、望むクラスにコンテキストを注入することができます。これはRoboGuice 2.0でそれを行う方法の小さなサンプルです(これを書いている時点でのベータ4)。

import Android.content.Context;
import Android.os.Build;
import roboguice.inject.ContextSingleton;

import javax.inject.Inject;

@ContextSingleton
public class DataManager {
    @Inject
    public DataManager(Context context) {
            Properties properties = new Properties();
            properties.load(context.getResources().getAssets().open("data.properties"));
        } catch (IOException e) {
        }
    }
}
11
user605331

私はいくつかの時点でこれを使用しました:

ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();

これは私がシステムサービスを受けて働いたときに使用した有効なコンテキストです。

しかし、私はこれをフレームワーク/ベースの変更にのみ使用し、Androidアプリケーションでは試しませんでした。

警告 あなたが知っていなければならないこと:この文脈で放送受信機に登録するとき、それは働かないでしょう、そしてあなたは得るでしょう:

Java.lang.SecurityException:指定された呼び出し元のパッケージAndroidがプロセスProcessRecordで実行されていない

8
ungalcrys

次のものを使用できます。

MainActivity.this.getApplicationContext();

MainActivity.Java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

他のクラス:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();
3
barwnikk

コトリンウェイ

マニフェスト:

<application Android:name="MyApplication">

</application>

MyApplication.kt

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

MyApplication.instanceからプロパティにアクセスできます。

3
phnmnn

によるとこのソース あなたはContextWrapperを拡張することによってあなた自身のコンテキストを得ることができます

public class SomeClass extends ContextWrapper {

    public SomeClass(Context base) {
      super(base);
    }

    public void someMethod() {
        // notice how I can use "this" for Context
        // this works because this class has it's own Context just like an Activity or Service
        startActivity(this, SomeRealActivity.class);

        //would require context too
        File cacheDir = getCacheDir();
    }
}

ContextWrapperのJavaDoc

その呼び出しのすべてを別のContextに単純に委任するContextの実装のプロキシ。元のContextを変更せずに動作を変更するためにサブクラス化することができます。

3
BlueWizard

コトリン

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

そしてContextのようになる

MyApp.mInstance

または

MyApp.getContext()
3
Khemraj

getAppContext()メソッドの本体が必要だと思います:

public static Context getAppContext()
   return MyApplication.context; 
3
Kognos

私はこれを手助けするためにシングルトンデザインパターンのバリエーションを使います。

import Android.app.Activity;
import Android.content.Context;

public class ApplicationContextSingleton {
    private static Activity gContext;

    public static void setContext( Activity activity) {
        gContext = activity;
    }

    public static Activity getActivity() {
        return gContext;
    }

    public static Context getContext() {
        return gContext;
    }
}

次に、 activity.onCreate() ApplicationContextSingleton.setContext( this );を呼び出し、 onDestroy() ApplicationContextSingleton.setContext( null );を呼び出します。

2
Bamaco

マニフェストファイルを変更したくない場合は、最初のアクティビティで手動でコンテキストを静的変数に格納できます。

public class App {
    private static Context context;

    public static void setContext(Context cntxt) {
        context = cntxt;
    }

    public static Context getContext() {
        return context;
    }
}

そしてあなたの活動が開始したときにコンテキストを設定するだけです:

// MainActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set Context
    App.setContext(getApplicationContext());

    // Other stuff
}

注: 他のすべての回答と同様に、これは潜在的なメモリリークです。

2
Sheharyar

だから私はそれがメモリリークを引き起こしているので、私は受け入れられた答えを修正し、これは私が思い付いたものです...

AndroidManifest.xml

    <application Android:name="com.xyz.MyApplication">
...

    </application>

MyApplication.Java

public class MyBakingAppContext extends Application {
    private static Object mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return (Context)mContext;
    }
}

私が実際にしたことは、コンテキストをオブジェクトに割り当て、そのオブジェクトをコンテキストとして返すことです(コンテキストにキャストします)。お役に立てば幸いです。

1
DevMike01

私はちょうど Vapor API と呼ばれるAndroid用のjQuery風のフレームワークをリリースしました。これはアプリ開発をより簡単にすることを目的としています。

中央の $ファサードクラス は、 WeakReference (Ethan Nicholasによる、これに関する素晴らしいJavaブログ記事へのリンク)を、現在のActivityコンテキストに維持します。

$.act()

WeakReferenceは、ガベージコレクションが元のオブジェクトを取り戻すのを妨げずに参照を維持するので、メモリリークの問題は発生しません。

もちろん、$.act()がnullを返す可能性があるという危険性があります。私はまだこのシナリオに出くわしていないので、それは言及する価値がある、おそらく最小のリスクです。

VaporActivityクラスとして Activity を使用していない場合は、手動でコンテキストを設定することもできます。

$.act(Activity);

また、 Vapor API フレームワークの多くはこのストアドコンテキストを本質的に使用しているため、フレームワークを使用することにした場合はまったく自分で格納する必要はありません。詳細とサンプルについては site を調べてください。

それが役立つことを願っています:)

1
Darius

何らかの理由でアプリケーションやアクティビティを拡張するものだけでなく、何らかのクラスでアプリケーションコンテキストが必要な場合は、ファクトリクラスやヘルパークラスなどがあります。次のシングルトンをアプリに追加できます。

public class GlobalAppContextSingleton {
    private static GlobalAppContextSingleton mInstance;
    private Context context;

    public static GlobalAppContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized GlobalAppContextSingleton getSync() {
        if (mInstance == null) mInstance = 
                new GlobalAppContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }
}

それから、あなたのアプリケーションクラスのonCreateでそれを初期化します。

GlobalAppContextSingleton.getInstance().initialize(this);

呼び出してどこでも使用できます

GlobalAppContextSingleton.getInstance().getApplicationContext()

ただし、この方法をアプリケーションのコンテキスト以外には推奨しません。それはメモリリークを引き起こす可能性があるので。

1
Versa

Rohitの答えは正しいようです。ただし、AndroidStudioの「インスタントラン」は、私の知る限り、コードにstatic Context属性が含まれていないことに依存しています。

1
payne

kotlinでは、コンパニオンオブジェクトにContext/App Contextを置くと、まだ警告Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)が生成されます

または、次のようなものを使用する場合:

    companion object {
        lateinit var instance: MyApp
    }

Applicationクラスとその子孫はContextであるため、メモリリークを発見しないようにリントをだますだけで、Appインスタンスはメモリリークを発生させる可能性があります。

または、機能的なインターフェイスまたは機能的なプロパティを使用して、アプリのコンテキストを取得できます。

オブジェクトクラスを作成するだけです。

object CoreHelper {
    lateinit var contextGetter: () -> Context
}

または、null許容型を使用してより安全に使用できます。

object CoreHelper {
    var contextGetter: (() -> Context)? = null
}

appクラスに次の行を追加します。


class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        CoreHelper.contextGetter = {
            this
        }
    }
}

マニフェストでアプリ名を. MyAppに宣言します


    <application
            Android:name=".MyApp"

コンテキストを取得するには、次のように呼び出します。

CoreHelper.contextGetter()

// or if you use the nullable version
CoreHelper.contextGetter?.invoke()

それが役立つことを願っています。

0
Hayi Nukman