静的メソッド内で現在のContext
インスタンスを取得する方法はありますか?
私はそのように探しています。なぜなら私はそれが変わるたびに 'Context'インスタンスを保存するのが嫌だからです。
これを行う:
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()
を呼び出します。
アプリケーションコンテキストを取得するための便利な方法を必要とするアプリの大多数は、 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);
}
ハッピーコーディング!
いいえ、ありません。残念なことに、あなたはActivity
またはContext
の他のサブクラスの1つからgetApplicationContext()
を呼び出そうとしています。また、 this という質問は多少関係しています。
アプリケーションコンテキストを取得することについて話していると仮定して、私は@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 でより詳細なバージョンを読むことができます。
これは、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 の解決策を使用することをお勧めします。
それはあなたがコンテキストを使用しているものに依存します。私はその方法の少なくとも一つの欠点を考えることができます:
AlertDialog.Builder
でAlertDialog
を作成しようとしている場合、Application
コンテキストは機能しません。現在のActivity
...の文脈が必要だと思います。
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) {
}
}
}
私はいくつかの時点でこれを使用しました:
ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();
これは私がシステムサービスを受けて働いたときに使用した有効なコンテキストです。
しかし、私はこれをフレームワーク/ベースの変更にのみ使用し、Androidアプリケーションでは試しませんでした。
警告 あなたが知っていなければならないこと:この文脈で放送受信機に登録するとき、それは働かないでしょう、そしてあなたは得るでしょう:
Java.lang.SecurityException:指定された呼び出し元のパッケージAndroidがプロセスProcessRecordで実行されていない
次のものを使用できます。
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();
コトリンウェイ :
マニフェスト:
<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からプロパティにアクセスできます。
によるとこのソース あなたは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();
}
}
その呼び出しのすべてを別のContextに単純に委任するContextの実装のプロキシ。元のContextを変更せずに動作を変更するためにサブクラス化することができます。
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()
getAppContext()
メソッドの本体が必要だと思います:
public static Context getAppContext()
return MyApplication.context;
私はこれを手助けするためにシングルトンデザインパターンのバリエーションを使います。
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 );
を呼び出します。
マニフェストファイルを変更したくない場合は、最初のアクティビティで手動でコンテキストを静的変数に格納できます。
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
}
注: 他のすべての回答と同様に、これは潜在的なメモリリークです。
だから私はそれがメモリリークを引き起こしているので、私は受け入れられた答えを修正し、これは私が思い付いたものです...
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;
}
}
私が実際にしたことは、コンテキストをオブジェクトに割り当て、そのオブジェクトをコンテキストとして返すことです(コンテキストにキャストします)。お役に立てば幸いです。
私はちょうど Vapor API と呼ばれるAndroid用のjQuery風のフレームワークをリリースしました。これはアプリ開発をより簡単にすることを目的としています。
中央の $
ファサードクラス は、 WeakReference
(Ethan Nicholasによる、これに関する素晴らしいJavaブログ記事へのリンク)を、現在のActivity
コンテキストに維持します。
$.act()
WeakReference
は、ガベージコレクションが元のオブジェクトを取り戻すのを妨げずに参照を維持するので、メモリリークの問題は発生しません。
もちろん、$.act()
がnullを返す可能性があるという危険性があります。私はまだこのシナリオに出くわしていないので、それは言及する価値がある、おそらく最小のリスクです。
VaporActivity
クラスとして Activity
を使用していない場合は、手動でコンテキストを設定することもできます。
$.act(Activity);
また、 Vapor API フレームワークの多くはこのストアドコンテキストを本質的に使用しているため、フレームワークを使用することにした場合はまったく自分で格納する必要はありません。詳細とサンプルについては site を調べてください。
それが役立つことを願っています:)
何らかの理由でアプリケーションやアクティビティを拡張するものだけでなく、何らかのクラスでアプリケーションコンテキストが必要な場合は、ファクトリクラスやヘルパークラスなどがあります。次のシングルトンをアプリに追加できます。
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()
ただし、この方法をアプリケーションのコンテキスト以外には推奨しません。それはメモリリークを引き起こす可能性があるので。
Rohitの答えは正しいようです。ただし、AndroidStudioの「インスタントラン」は、私の知る限り、コードにstatic Context
属性が含まれていないことに依存しています。
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()
それが役立つことを願っています。