Contextを深く理解する
5907 ワード
Contextとは?
Android開発ではContext呼び出しから離れられないシステム関連のAPIがContextを使用しなければならないことはよく知られていると思います.私たちは彼女をコンテキスト環境と理解することができます.おそらく、システムAPIを呼び出すときに使用する必要があるグローバル変数の山が格納されています.文字はずっと私の言いたいことを表現しにくいので、原理を分析しましょう.
Contextはどこから来ましたか?
Androidアプリケーションの開発にはActivityが必要で、ActivityでさまざまなシステムAPIを呼び出す必要があります.例えば、
この行のコードは簡単に見えますが、Activityで呼び出さないとどうやってstringを取得しますか?
Contextオブジェクトが必要ですが、Activityではなぜ必要ありませんか?
答えは、ActivityはもともとContextであり、Contextから継承されています.Activityを開くと、彼の継承順序は次のようにわかります.
Activity -> ContextThemeWrapper -> ContextWrapper -> Context
Contextは抽象クラスで、すべての方法は実装されていません.ContextWrapperはすべての方法を実装していますが、彼はエージェントにすぎません.ソースコードを開くと、彼はこのように見えます.
彼はmBaseの方法を呼び出すだけで、(この設計モードではエージェントモードProxyと呼ばれています)、私たちはこのmBaseがどこから来たのかを明らかにしなければなりません!
ソースコードを見ると2つの場所にmBaseが設置されているだけで、
1つはコンストラクション関数、1つはattachBaseContextです.
まず構造関数を分析しましょう.Activityは彼女から受け継がれているので、Activityがどのように作成されたのかを分析しました.Activityの作成プロセスは複雑なので、このポイントは彼ではありません.私はここで直接結果を出しました.Activityが作成されたときに呼び出されたのはパラメータなし構造関数です.したがって、mBaseはコンストラクション関数ではなく、attachBaseContextから来ています.次に、ActivityがattachBaseContext()メソッドを呼び出した場所を分析します.
Activityソースコードを確認すると呼び出し先が見つかります
Activity.attachメソッドframeworkがActivityを作成するときに呼び出されます.このcontextパラメータが何であるかを知るにはframeworkコードから見なければなりません.
コード:android.app.ActivityThread
見て、contextはここのappContextです.彼はContextImplオブジェクトです.はい、ContextImplが本当の実装者であることを知っています.
だからgetString()の本当の呼び出しはContextImplです.getResource.getString()、getString()の真の実装はResource(android.content.res.Resources)にある.
Contextは何種類ありますか? Activity: を分析しました Service:ContextWrapperからActivityと同じ を継承 BroadcastReceiver : onReceiver(Context context ) Application:
すべてのContextが実際に実装されていることを覚えておいてください.
Activity、ServiceのContextは、グローバル一意ではなく作成されるたびに作成されるので、Activity、ServiceをグローバルContext参照としないでください.これにより、Activityは破棄されず、常に参照されています.
では、どのようなContextがグローバルリファレンスを行うことができますか?
答えは:Application、もしあなたがカスタマイズしたApplicationがなければどのようにこのContextを取得しますか?Contextには
getApplicationContext()メソッドは、ContextImplで次のように実装されています.
android.app.ContextImpl
android.app.LoadedApk
このmApplicationオブジェクトがプログラムのApplicationです.彼をカスタマイズしたアプリケーションに変えることができます
BroadcastReceiverのContext
コードから、彼はアプリケーションのContextImplオブジェクトなので、グローバルな
Android開発ではContext呼び出しから離れられないシステム関連のAPIがContextを使用しなければならないことはよく知られていると思います.私たちは彼女をコンテキスト環境と理解することができます.おそらく、システムAPIを呼び出すときに使用する必要があるグローバル変数の山が格納されています.文字はずっと私の言いたいことを表現しにくいので、原理を分析しましょう.
Contextはどこから来ましたか?
Androidアプリケーションの開発にはActivityが必要で、ActivityでさまざまなシステムAPIを呼び出す必要があります.例えば、
String string = getString(R.string.app_name);
この行のコードは簡単に見えますが、Activityで呼び出さないとどうやってstringを取得しますか?
Context context;
context.getString(R.string.app_name);
Contextオブジェクトが必要ですが、Activityではなぜ必要ありませんか?
答えは、ActivityはもともとContextであり、Contextから継承されています.Activityを開くと、彼の継承順序は次のようにわかります.
Activity -> ContextThemeWrapper -> ContextWrapper -> Context
Contextは抽象クラスで、すべての方法は実装されていません.ContextWrapperはすべての方法を実装していますが、彼はエージェントにすぎません.ソースコードを開くと、彼はこのように見えます.
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources()
{
return mBase.getResources();
}
彼はmBaseの方法を呼び出すだけで、(この設計モードではエージェントモードProxyと呼ばれています)、私たちはこのmBaseがどこから来たのかを明らかにしなければなりません!
ソースコードを見ると2つの場所にmBaseが設置されているだけで、
public ContextWrapper(Context base) {
mBase = base;
}
/**
* Set the base context for this ContextWrapper. All calls will then be
* delegated to the base context. Throws
* IllegalStateException if a base context has already been set.
*
* @param base The new base context for this wrapper.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
1つはコンストラクション関数、1つはattachBaseContextです.
まず構造関数を分析しましょう.Activityは彼女から受け継がれているので、Activityがどのように作成されたのかを分析しました.Activityの作成プロセスは複雑なので、このポイントは彼ではありません.私はここで直接結果を出しました.Activityが作成されたときに呼び出されたのはパラメータなし構造関数です.したがって、mBaseはコンストラクション関数ではなく、attachBaseContextから来ています.次に、ActivityがattachBaseContext()メソッドを呼び出した場所を分析します.
Activityソースコードを確認すると呼び出し先が見つかります
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
Activity.attachメソッドframeworkがActivityを作成するときに呼び出されます.このcontextパラメータが何であるかを知るにはframeworkコードから見なければなりません.
コード:android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
} catch (Exception e) {
}
try {
if (activity != null) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
見て、contextはここのappContextです.彼はContextImplオブジェクトです.はい、ContextImplが本当の実装者であることを知っています.
だからgetString()の本当の呼び出しはContextImplです.getResource.getString()、getString()の真の実装はResource(android.content.res.Resources)にある.
Contextは何種類ありますか?
すべてのContextが実際に実装されていることを覚えておいてください.
Activity、ServiceのContextは、グローバル一意ではなく作成されるたびに作成されるので、Activity、ServiceをグローバルContext参照としないでください.これにより、Activityは破棄されず、常に参照されています.
では、どのようなContextがグローバルリファレンスを行うことができますか?
答えは:Application、もしあなたがカスタマイズしたApplicationがなければどのようにこのContextを取得しますか?Contextには
getApplicationContext()メソッドは、ContextImplで次のように実装されています.
android.app.ContextImpl
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
android.app.LoadedApk
Application getApplication() {
return mApplication;
}
このmApplicationオブジェクトがプログラムのApplicationです.彼をカスタマイズしたアプリケーションに変えることができます
BroadcastReceiverのContext
Application app = packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + packageInfo.getPackageName()
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
コードから、彼はアプリケーションのContextImplオブジェクトなので、グローバルな