私が見たAndroidコードのさまざまなビットで:
public class MyActivity extends Activity {
public void method() {
mContext = this; // since Activity extends Context
mContext = getApplicationContext();
mContext = getBaseContext();
}
}
しかし、どの状況が望ましいか、どのような状況で使用されるべきかについての適切な説明は見つかりません。
これに関するドキュメントへのポインタと、間違ったものが選択された場合に何が壊れる可能性があるかについてのガイダンスをいただければ幸いです。
Androidのコンテキストに関してはドキュメントがまばらであることに同意しますが、さまざまなソースからいくつかの事実をまとめることができます。
このブログ投稿 公式のGoogle Android開発者ブログでは、主にメモリリークに対処するために書かれましたが、コンテキストに関するいくつかの良い情報も提供しています
通常のAndroidアプリケーションでは、通常、2種類のコンテキスト、アクティビティ、およびアプリケーションがあります。
この記事を少し読むと、この2つの違いと、アクティビティコンテキスト(this
)を使用するのではなく、アプリケーションコンテキスト(Activity.getApplicationContext()
)の使用を検討する場合の違いについて説明します。基本的に、アプリケーションコンテキストはアプリケーションに関連付けられ、アプリのライフサイクルを通じて常に同じです。アクティビティコンテキストはアクティビティに関連付けられ、画面の向きの変更中にアクティビティが破棄されると何度も破棄される可能性があるため、そのような。
Android SDKに取り組んでいるGoogleエンジニアの1人であるDianne Hackbornからの投稿以外に、getBaseContext()をいつ使用するかについて、本当に何も見つかりませんでした。
GetBaseContext()を使用せずに、持っているコンテキストを使用してください。
Android-developers newsgroup の投稿からでした。Androidで作業している少数の人々が実際にそのニュースグループを監視し、回答するため、そこで質問することを検討することもできます質問。
したがって、全体的には、可能な場合はグローバルアプリケーションコンテキストを使用することをお勧めします。
context
name__の使用に関して私が見つけたものは次のとおりです。
1)。Activity
name__自体の中で、レイアウトとメニューの拡張、コンテキストメニューの登録、ウィジェットのインスタンス化、他のアクティビティの開始、新しいthis
name__の作成にIntent
name__を使用Activity
name__、インスタンス化設定、またはActivity
name__で使用可能な他のメソッド。
レイアウトを膨らませる:
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
name __:を開始します
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
name__またはcontext
name__はクラスのコンテキスト(アクティビティなど)です。
Activity
name__コンテキスト置換:
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
name__コンテキスト置換:
public class MyContentObserver extends ContentObserver {
private Context mContext;
public MyContentObserver(Handler handler, Context context) {
super(handler);
mContext = context;
}
}
4)。BroadcastReceiver
name__(インライン/埋め込みレシーバーを含む)には、レシーバー自身のコンテキストを使用します。
外部BroadcastReceiver
name __:
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
name __:
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();
}
}
最後に、Androidのフレームワーク開発者からのアドバイスに従ってgetBaseContext()
を使用しないでください。
UPDATE:Context
name__の使用例を追加します。
私は数日前にこのスレッドを読み、同じ質問を自問しました。これを読んだ後の私の決定は簡単でした。常にapplicationContextを使用します。
しかし、私はこれで問題に遭遇し、それを見つけるのに数時間を費やし、それを解決するのに数秒を費やしました...(1つの単語を変える...)
LayoutInflaterを使用して、スピナーを含むビューを膨張させています。
そのため、次の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);
私が気づいたこと:applicationContextでlinearLayoutをインスタンス化した場合、アクティビティでスピナーをクリックすると、dalvik仮想マシン(コードからではなく、多くの時間を費やした理由)からのキャッチされない例外が発生します私の間違いがどこにあったかを見つける時間...)。
BaseContextを使用する場合、それで問題ありません。コンテキストメニューが開き、選択項目から選択できるようになります。
だからここに私の結論があります:あなたのアクティビティでcontextMenuを扱うときにbaseContextが必要であると思います(それをさらにテストしていません)...
テストはAPI 8を使用してコーディングされ、HTC Desire、Android 2.3.3でテストされました。
私のコメントがこれまでに退屈していないことを願っています。ハッピーコーディング;-)
まず、可能な限りappcontextを使用する必要があることに同意します。アクティビティの「this」。 basecontextは必要ありませんでした。
私のテストでは、ほとんどの場合、交換できます。ほとんどの場合、コンテキストを取得する理由は、ファイル、設定、データベースなどにアクセスすることです。これらのデータは、最終的にアプリのプライベートデータフォルダー(/ data/data /)のファイルとして反映されます。どのコンテキストを使用しても、それらは同じフォルダ/ファイルにマップされるため、問題ありません。
それが私が観察したことです。たぶんそれらを区別する必要がある場合があります。
場合によっては、スレッド内で何かを実行するときに、アプリケーションコンテキストではなくアクティビティコンテキストを使用できます。スレッドの実行が完了し、結果を呼び出し側アクティビティに返す必要がある場合、ハンドラーでそのコンテキストが必要です。
((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
簡単な言葉で
getApplicationContext()
は、メソッド名が示すように、アプリ内のどこからでもアクセスできるアプリケーション全体の詳細をアプリに認識させます。したがって、サービスバインディング、ブロードキャスト登録などでこれを利用できます。Application context
は、アプリが終了するまで有効です。
getActivity()
またはthis
は、application context
によって提供されるアプリレベルの詳細も表示される現在の画面をアプリに認識させます。したがって、Window
ActionBar
Fragementmanger
など、現在の画面について知りたいことはすべて、このコンテキストで使用できます。基本的にActivity
はContext
を拡張します。このコンテキストは、現在のコンポーネント(アクティビティ)が有効になるまで有効です
混乱は、コンテキストにアクセスする方法が多数あり、(表面上)識別可能な違いがないことに起因しています。以下は、アクティビティのコンテキストにアクセスできる最も一般的な4つの方法です。
getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new
コンテキストとは何ですか?私は個人的に、いつでもコンテキストをアプリケーションの状態と考えています。アプリケーションコンテキストは、アプリケーションのグローバルまたは基本構成を表し、アクティビティまたはサービスはそれに基づいて構築でき、アプリケーションの構成インスタンスまたはその遷移状態を表します。
Android.content.Contextのソースを見ると、Contextは抽象クラスであり、クラスに関するコメントは次のとおりです。
アプリケーション環境に関するグローバル情報へのインターフェース。これは、Androidシステムによって実装が提供される抽象クラスです。 application-specific
リソースおよびクラスへのアクセスと、アクティビティの起動、インテントのブロードキャストおよび受信などのapplication-level
操作のアップコールが可能になります。アプリケーションレベルおよびシステムレベルのリソースにアクセスするための実装。アプリケーションレベルのリソースは、文字列リソース[getResources()]
またはアセット[getAssets()]
のようなものにアクセスしている可能性があり、システムレベルのリソースは、Context.getSystemService().
でアクセスするものです
実際問題として、メソッドに関するコメントを見てください。これらはこの概念を補強しているようです:
getSystemService()
:名前でsystem-level
サービスへのハンドルを返します。返されるオブジェクトのクラスは、要求された名前によって異なります。 getResources()
:アプリケーションのパッケージのリソースインスタンスを返します。 getAssets()
:アプリケーションのパッケージのリソースインスタンスを返します。 Context抽象クラスでは、上記のすべてのメソッドが抽象であることを指摘する価値があります。 getSystemService(Class)の1つのインスタンスのみが実装を持ち、抽象メソッドを呼び出します。つまり、これらの実装は、主に以下を含む実装クラスによって提供される必要があります。
ContextWrapper
Application
Activity
Service
IntentService
APIドキュメントを見ると、クラスの階層は次のようになっています。
コンテキスト
| — ContextWrapper
| — —アプリケーション
| — — ContextThemeWrapper
| — — — —アクティビティ
| — —サービス
| — — — IntentService
Context
自体が洞察を提供していないことがわかっているので、ツリーを下に移動してContextWrapper
を見て、そこにもあまりないことがわかります。 ApplicationはContextWrapper
を拡張するので、ContextWrapper
によって提供される実装をオーバーライドしないため、そこをあまり見る必要もありません。これは、Contextの実装がOSによって提供され、API
から隠されていることを意味します。 ContextImplクラスのソースを見ると、Contextの具体的な実装を見ることができます。
getBaseContext
(JavaとAndroidの両方に非常に緑色のnoob)からトーストするときに、これとonClick
のみを使用しました。私はクリッカーがアクティビティに直接あるときにこれを使用し、匿名の内部クリッカーでgetBaseContext
を使用する必要があります。それはgetBaseContext
のトリックだと思いますが、おそらく内部クラスが隠れているアクティビティのコンテキストを返しているのでしょう。