Android組件管理框架:Android應用上下文Context

關於做者java

郭孝星,程序員,吉他手,主要從事Android平臺基礎架構方面的工做,歡迎交流技術方面的問題,能夠去個人Github提issue或者發郵件至guoxiaoxingse@163.com與我交流。android

第一次閱覽本系列文章,請參見導讀,更多文章請參見文章目錄git

文章目錄程序員

  • 一 Context與四大組件的關係
    • 1.1 Activity的建立流程
    • 1.2 Service的建立流程
    • 1.3 靜態廣播的建立流程
    • 1.4 Content Provider的建立流程
    • 1.5 Application的建立流程
  • 二 Context的建立流程
    • 2.1 Activity Context的建立流程
    • 2.2 Service Context的建立流程
    • 2.3 靜態廣播 Context的建立流程
    • 2.4 Content Provider Context的建立流程
    • 2.5 Application Context的建立流程
  • 三 Context的綁定流程
    • 3.1 Activity與Context的綁定流程
    • 3.2 Service與Context的綁定流程
    • 3.3 靜態廣播與Context的綁定流程
    • 3.4 Content Provider與Context的綁定流程
    • 3.5 Application與Context的綁定流程

提到Context你們並不陌生,它是Android裏的一個上帝類,啓動四大組件、獲取資源、獲取類加載器等重要功能都經過Context 來完成,Activity、Service與Application也都派生自Context,Broadcast Receiver與Content Provider與Context 也有着密切的聯繫。github

Context類圖以下所示:架構

能夠發現Context是個抽象類,它的具體實現類是ContextImpl,ContextWrapper是個包裝類,內部的成員變量mBase指向的也是個ContextImpl對象,ContextImpl完成了 實際的功能,Activity、Service與Application都直接或者間接的繼承ContextWrapper。app

咱們知道Context表示的應用的上下文環境,四大組件都與Context有密切的關係,在建立組件的時候會同時建立Context,並將二者進行綁定,咱們來看看四大組件與 Context之間的關係。ide

一 Context與四大組件的關係

1.1 Activity的建立流程

public final class ActivityThread {
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
    
            ActivityInfo aInfo = r.activityInfo;
            // 1. 獲取LoadedApk對象。
            if (r.packageInfo == null) {
                r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                        Context.CONTEXT_INCLUDE_CODE);
            }
    
            ComponentName component = r.intent.getComponent();
            if (component == null) {
                component = r.intent.resolveActivity(
                    mInitialApplication.getPackageManager());
                r.intent.setComponent(component);
            }
    
            if (r.activityInfo.targetActivity != null) {
                component = new ComponentName(r.activityInfo.packageName,
                        r.activityInfo.targetActivity);
            }
    
            // 2. 建立Activity對象。
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                r.intent.setExtrasClassLoader(cl);
                r.intent.prepareToEnterProcess();
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                // 3. 建立Application對象。
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
                // ...log
                
                if (activity != null) {
                    // 4. 建立ContextImpl對象。
                    Context appContext = createBaseContextForActivity(r, activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                    if (r.overrideConfig != null) {
                        config.updateFrom(r.overrideConfig);
                    }
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                            + r.activityInfo.name + " with config " + config);
                    Window window = null;
                    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                        window = r.mPendingRemoveWindow;
                        r.mPendingRemoveWindow = null;
                        r.mPendingRemoveWindowManager = null;
                    }
                    activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor, window);
    
                    if (customIntent != null) {
                        activity.mIntent = customIntent;
                    }
                    r.lastNonConfigurationInstances = null;
                    activity.mStartedActivity = false;
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        // 5. 執行Activity的onCreate()回調方法。
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onCreate()");
                    }
                    r.activity = activity;
                    r.stopped = true;
                    if (!r.activity.mFinished) {
                        activity.performStart();
                        r.stopped = false;
                    }
                    if (!r.activity.mFinished) {
                        if (r.isPersistable()) {
                            if (r.state != null || r.persistentState != null) {
                                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                        r.persistentState);
                            }
                        } else if (r.state != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                        }
                    }
                    if (!r.activity.mFinished) {
                        activity.mCalled = false;
                        if (r.isPersistable()) {
                            mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                    r.persistentState);
                        } else {
                            mInstrumentation.callActivityOnPostCreate(activity, r.state);
                        }
                        if (!activity.mCalled) {
                            throw new SuperNotCalledException(
                                "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onPostCreate()");
                        }
                    }
                }
                r.paused = true;
    
                mActivities.put(r.token, r);
    
            } catch (SuperNotCalledException e) {
                throw e;
    
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            return activity;
        }
}
複製代碼

Activity的建立流程以下所示:函數

  1. 獲取LoadedApk對象。
  2. 建立Activity對象。
  3. 建立Application對象。
  4. 建立ContextImpl對象。
  5. 執行Activity的onCreate()回調方法。

1.2 Service的建立流程

public final class ActivityThread {
    
    private void handleCreateService(CreateServiceData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            // 1. 獲取LoadedApk對象。
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
            Service service = null;
            try {
                // 2. 建立Service對象。
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = (Service) cl.loadClass(data.info.name).newInstance();
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
                // 3. 建立ContextImpl對象。
                ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                context.setOuterContext(service);
    
                // 4. 建立Application對象。
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManagerNative.getDefault());
                // 5. 執行Service的onCreate()回調方法。
                service.onCreate();
                mServices.put(data.token, service);
                try {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to create service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
        }
}
複製代碼

Service的建立流程以下所示:ui

  1. 獲取LoadedApk對象。
  2. 建立Service對象。
  3. 建立ContextImpl對象。
  4. 建立Application對象。
  5. 執行Service的onCreate()回調方法。

1.3 靜態廣播的建立流程

public final class ActivityThread {
    
    private void handleReceiver(ReceiverData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            String component = data.intent.getComponent().getClassName();
            // 1. 獲取LoadedApk對象。
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
    
            IActivityManager mgr = ActivityManagerNative.getDefault();
    
            BroadcastReceiver receiver;
            try {
                // 2. 建立BroadcastReceiver對象。
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                data.intent.setExtrasClassLoader(cl);
                data.intent.prepareToEnterProcess();
                data.setExtrasClassLoader(cl);
                receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
            } catch (Exception e) {
                // ...log
            }
    
            try {
                // 3. 建立Application對象。
                Application app = packageInfo.makeApplication(false, mInstrumentation);
    
                // ...log
    
                // 4. 獲取ContextImpl對象。
                ContextImpl context = (ContextImpl)app.getBaseContext();
                sCurrentBroadcastIntent.set(data.intent);
                receiver.setPendingResult(data);
                // 5. 回調onReceive()方法。
                receiver.onReceive(context.getReceiverRestrictedContext(),
                        data.intent);
            } catch (Exception e) {
                // ...log
            } finally {
                sCurrentBroadcastIntent.set(null);
            }
    
            if (receiver.getPendingResult() != null) {
                data.finish();
            }
        }   
}
複製代碼

靜態廣播的建立流程以下所示:

  1. 獲取LoadedApk對象。
  2. 建立BroadcastReceiver對象。
  3. 建立Application對象。
  4. 獲取ContextImpl對象。
  5. 回調onReceive()方法。

1.4 Content Provider的建立流程

public final class ActivityThread {
    
     private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {
            ContentProvider localProvider = null;
            IContentProvider provider;
            if (holder == null || holder.provider == null) {
                if (DEBUG_PROVIDER || noisy) {
                    Slog.d(TAG, "Loading provider " + info.authority + ": "
                            + info.name);
                }
                Context c = null;
                ApplicationInfo ai = info.applicationInfo;
                if (context.getPackageName().equals(ai.packageName)) {
                    c = context;
                } else if (mInitialApplication != null &&
                        mInitialApplication.getPackageName().equals(ai.packageName)) {
                    c = mInitialApplication;
                } else {
                    try {
                        // 1. 建立ContextImpl對象。
                        c = context.createPackageContext(ai.packageName,
                                Context.CONTEXT_INCLUDE_CODE);
                    } catch (PackageManager.NameNotFoundException e) {
                        // Ignore
                    }
                }
                if (c == null) {
                    // ...log
                    return null;
                }
                try {
                    // 2. 建立Content Provider對象。
                    final java.lang.ClassLoader cl = c.getClassLoader();
                    localProvider = (ContentProvider)cl.
                        loadClass(info.name).newInstance();
                    provider = localProvider.getIContentProvider();
                    if (provider == null) {
                        // ...log
                        return null;
                    }
                    if (DEBUG_PROVIDER) Slog.v(
                        TAG, "Instantiating local provider " + info.name);
                    // 3. 將ContextImpl對象綁定到Content Provider。
                    localProvider.attachInfo(c, info);
                } catch (java.lang.Exception e) {
                    // ...log
                    return null;
                }
            } else {
                provider = holder.provider;
                if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                        + info.name);
            }
    
            IActivityManager.ContentProviderHolder retHolder;
    
            synchronized (mProviderMap) {
                if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                        + " / " + info.name);
                IBinder jBinder = provider.asBinder();
                if (localProvider != null) {
                    ComponentName cname = new ComponentName(info.packageName, info.name);
                    ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                    if (pr != null) {
                        // ...log
                        provider = pr.mProvider;
                    } else {
                        holder = new IActivityManager.ContentProviderHolder(info);
                        holder.provider = provider;
                        holder.noReleaseNeeded = true;
                        pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                        mLocalProviders.put(jBinder, pr);
                        mLocalProvidersByName.put(cname, pr);
                    }
                    retHolder = pr.mHolder;
                } else {
                    ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                    if (prc != null) {
                        // ...log
                        if (!noReleaseNeeded) {
                            incProviderRefLocked(prc, stable);
                            try {
                                ActivityManagerNative.getDefault().removeContentProvider(
                                        holder.connection, stable);
                            } catch (RemoteException e) {
                                //do nothing content provider object is dead any way
                            }
                        }
                    } else {
                        ProviderClientRecord client = installProviderAuthoritiesLocked(
                                provider, localProvider, holder);
                        if (noReleaseNeeded) {
                            prc = new ProviderRefCount(holder, client, 1000, 1000);
                        } else {
                            prc = stable
                                    ? new ProviderRefCount(holder, client, 1, 0)
                                    : new ProviderRefCount(holder, client, 0, 1);
                        }
                        mProviderRefCountMap.put(jBinder, prc);
                    }
                    retHolder = prc.holder;
                }
            }
    
            return retHolder;
        }
}
複製代碼
  1. 建立ContextImpl對象。
  2. 建立Content Provider對象。
  3. 將ContextImpl對象綁定到Content Provider。

經過上面的分析咱們知道在四大組件建立的過程當中,都須要建立ContextImpl對象與Application對象,Application對象都是經過LoadedApk的makeApplication()方法來完成的,但 是ContextImpl對象的建立方法卻各不相同,咱們來看一看。

1.5 Application的建立流程

經過上述內容能夠發現,對於四大組件,Application的建立和獲取方式也是不盡相同的,具體說來:

  • Activity:經過LoadedApk的makeApplication()方法建立。
  • Service:經過LoadedApk的makeApplication()方法建立。
  • 靜態廣播:經過其回調方法onReceive()方法的第一個參數指向Application。
  • ContentProvider:沒法獲取Application,所以此時Application不必定已經初始化。

LoadedApk的makeApplication()方法以下所示:

public final class LoadedApk {
    
       public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
            // Application只會建立一次,若是Application對象已經存在則再也不建立,一個APK對應一個
            // LoadedApk對象,一個LoadedApk對象對應一個Application對象。
            if (mApplication != null) {
                return mApplication;
            }
    
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    
            Application app = null;
    
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
    
            try {
                // 1. 建立加載Application的ClassLoader對象。
                java.lang.ClassLoader cl = getClassLoader();
                if (!mPackageName.equals("android")) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                            "initializeJavaContextClassLoader");
                    initializeJavaContextClassLoader();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                // 2. 建立ContextImpl對象。
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                // 3. 建立Application對象。
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
                // 4. 將Application對象設置給ContextImpl。
                appContext.setOuterContext(app);
            } catch (Exception e) {
                if (!mActivityThread.mInstrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to instantiate application " + appClass
                        + ": " + e.toString(), e);
                }
            }
            // 5. 將Application對象添加到ActivityThread的Application列表中。
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
    
            if (instrumentation != null) {
                try {
                    // 6. 執行Application的回調方法onCreate()。
                    instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!instrumentation.onException(app, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            }
    
            // Rewrite the R 'constants' for all library apks.
            SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
                    .getAssignedPackageIdentifiers();
            final int N = packageIdentifiers.size();
            for (int i = 0; i < N; i++) {
                final int id = packageIdentifiers.keyAt(i);
                if (id == 0x01 || id == 0x7f) {
                    continue;
                }
    
                rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
            }
    
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
            return app;
        }
}
複製代碼

Application的建立流程以下所示:

  1. 建立加載Application的ClassLoader對象。
  2. 建立ContextImpl對象。
  3. 建立Application對象。
  4. 將Application對象設置給ContextImpl。
  5. 將Application對象添加到ActivityThread的Application列表中。
  6. 執行Application的回調方法onCreate()。

👉 注:Application只會建立一次,若是Application對象已經存在則再也不建立,一個APK對應一個LoadedApk對象,一個LoadedApk對象 對應一個Application對象。

Application對象的構建時經過Instrumentation的newApplication()方法完成的。

public class Instrumentation {
   static public Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
       Application app = (Application)clazz.newInstance();
       app.attach(context);
       return app;
   } 
}
複製代碼

這裏咱們再注意一下ContextImpl的setOuterContext()方法,它用來設置外部Context,可是不一樣場景下設置的對象不一樣,具體說來:

  • makeApplication():Outer Context設置的是Application。
  • createBaseContextForActivity():Outer Context設置的是Activity。
  • handleCreateService():Outer Context設置的是Service。
  • BroadcastReceiver/Provider:Outer Context設置的是默認的ContextImpl。

二 Context的建立流程

前面說過四大組件獲取ContextImpl對象的方式是各不相同的,具體說來:

  • Activity:ContextImpl的createActivityContext()方法。
  • Service:ContextImpl的createAppContext()方法。
  • 靜態廣播:ContextImpl的getBaseContext()方法。
  • Content Provider:ContextImpl的createPackageContext()方法。

咱們分別來看看。

2.1 Activity Context的建立流程

Activity Context的建立是經過createBaseContextForActivity()方法來完成,以下所示:

public final class ActivityThread {
    
     private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
            int displayId = Display.DEFAULT_DISPLAY;
            try {
                displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
    
            // 1. 建立ContextImpl對象。
            ContextImpl appContext = ContextImpl.createActivityContext(
                    this, r.packageInfo, r.token, displayId, r.overrideConfig);
            // 2. 設置Outer Context。
            appContext.setOuterContext(activity);
            // 3. 設置Base Context。
            Context baseContext = appContext;
    
            final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
            // ... debug code
            return baseContext;
        }
}
複製代碼
  1. 建立ContextImpl對象。
  2. 設置Outer Context。
  3. 設置Base Context。

ContextImpl對象的構建其實就是將ActivityThread、LoadedApk、activityToke、displayId、Configuration等重要信息 傳遞給ContextImpl,這樣ContextImpl就擁有了一個應用的全部信息,具體以下所示:

class ContextImpl extends Context {
    
     static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) {
           if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
           return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
                   null, overrideConfiguration, displayId);
       } 
}
複製代碼

2.2 Service Context的建立流程

建立Service Context,建立Service的時候用的就是這個方法來建立ContextImpl對象。

class ContextImpl extends Context {
    
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
    }
}
複製代碼

能夠發現Activity Context在構建的時候比Service Context多傳了activityToken和overrideConfiguration對象。

2.3 靜態廣播 Context的建立流程

class ContextWraper extends Context {
   public Context getBaseContext() {
        return mBase;
    }
}
複製代碼

這個mBase指向的也是ContextImpl對象,它是在構造ContextWraper對象的時候傳遞進來的。這個ContextImpl對象其實是Activity或者 Service的ContextImpl對象,下面咱們會具體講。

2.4 Content Provider Context的建立流程

建立Content Provider Context。

class ContextImpl extends Context {
       @Override
       public Context createPackageContext(String packageName, int flags) throws NameNotFoundException {
           return createPackageContextAsUser(packageName, flags,
                   mUser != null ? mUser : Process.myUserHandle());
       }
   
       @Override
       public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) throws NameNotFoundException {
           if (packageName.equals("system") || packageName.equals("android")) {
               return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                       user, flags, mDisplay, null, Display.INVALID_DISPLAY);
           }
   
           // 1. 獲取LoadedApk對象。
           LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                   flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
           if (pi != null) {
               // 2. 構造ContextImpl對象。
               ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
                       user, flags, mDisplay, null, Display.INVALID_DISPLAY);
               if (c.mResources != null) {
                   return c;
               }
           }
   
           // Should be a better exception.
           throw new PackageManager.NameNotFoundException(
                   "Application package " + packageName + " not found");
       } 
}
複製代碼

Content Provider Context在構建的時候多傳了一個UserHandle對象,該對象用來描述當前設備的用戶信息。

2.5 Application Context的建立流程

建立Application Context。

class ContextImpl extends Context {
    
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
    }
}
複製代碼

Application Context與Service Context的建立都是調用createAppContext()方法。

能夠發現,除了靜態廣播直接調用getBaseContext()獲取ContextImpl對象之外,其餘的都是經過ContextImpl的構造方法來構建ContextImpl對象,以下所示:

class ContextImpl extends Context {
    
     private ContextImpl(ContextImpl container, ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags, Display display, Configuration overrideConfiguration, int createDisplayWithId) {
            mOuterContext = this;
    
            // 1. 建立默認的應用目錄/data/data/packageName。
            if ((flags & (Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE
                    | Context.CONTEXT_DEVICE_PROTECTED_STORAGE)) == 0) {
                final File dataDir = packageInfo.getDataDirFile();
                if (Objects.equals(dataDir, packageInfo.getCredentialProtectedDataDirFile())) {
                    flags |= Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
                } else if (Objects.equals(dataDir, packageInfo.getDeviceProtectedDataDirFile())) {
                    flags |= Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
                }
            }
    
            // 2. 複製mMainThread、mActivityToken、mPackageInfo、mResourcesManager等重要成員變量。
            mMainThread = mainThread;
            mActivityToken = activityToken;
            mFlags = flags;
    
            if (user == null) {
                user = Process.myUserHandle();
            }
            mUser = user;
    
            mPackageInfo = packageInfo;
            mResourcesManager = ResourcesManager.getInstance();
    
            final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
                    ? createDisplayWithId
                    : (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
    
            CompatibilityInfo compatInfo = null;
            if (container != null) {
                compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
            }
            if (compatInfo == null) {
                compatInfo = (displayId == Display.DEFAULT_DISPLAY)
                        ? packageInfo.getCompatibilityInfo()
                        : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
            }
    
            // 3. 構建Resouces對象。
            Resources resources = packageInfo.getResources(mainThread);
            if (resources != null) {
                if (displayId != Display.DEFAULT_DISPLAY
                        || overrideConfiguration != null
                        || (compatInfo != null && compatInfo.applicationScale
                                != resources.getCompatibilityInfo().applicationScale)) {
    
                    if (container != null) {
                        // This is a nested Context, so it can't be a base Activity context.
                        // Just create a regular Resources object associated with the Activity.
                        resources = mResourcesManager.getResources(
                                activityToken,
                                packageInfo.getResDir(),
                                packageInfo.getSplitResDirs(),
                                packageInfo.getOverlayDirs(),
                                packageInfo.getApplicationInfo().sharedLibraryFiles,
                                displayId,
                                overrideConfiguration,
                                compatInfo,
                                packageInfo.getClassLoader());
                    } else {
                        // This is not a nested Context, so it must be the root Activity context.
                        // All other nested Contexts will inherit the configuration set here.
                        resources = mResourcesManager.createBaseActivityResources(
                                activityToken,
                                packageInfo.getResDir(),
                                packageInfo.getSplitResDirs(),
                                packageInfo.getOverlayDirs(),
                                packageInfo.getApplicationInfo().sharedLibraryFiles,
                                displayId,
                                overrideConfiguration,
                                compatInfo,
                                packageInfo.getClassLoader());
                    }
                }
            }
            mResources = resources;
    
            // 4. 建立Display對象。
            mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
                    : mResourcesManager.getAdjustedDisplay(displayId, mResources.getDisplayAdjustments());
    
            if (container != null) {
                mBasePackageName = container.mBasePackageName;
                mOpPackageName = container.mOpPackageName;
            } else {
                mBasePackageName = packageInfo.mPackageName;
                ApplicationInfo ainfo = packageInfo.getApplicationInfo();
                if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
                    // Special case: system components allow themselves to be loaded in to other
                    // processes. For purposes of app ops, we must then consider the context as
                    // belonging to the package of this process, not the system itself, otherwise
                    // the package+uid verifications in app ops will fail.
                    mOpPackageName = ActivityThread.currentPackageName();
                } else {
                    mOpPackageName = mBasePackageName;
                }
            }
    
            // 5. 建立ContentResolver對象。
            mContentResolver = new ApplicationContentResolver(this, mainThread, user);
        }
}
複製代碼

咱們首先來看看這個構造函數的參數,以下所示:

  • ContextImpl container:容器Context,通常置爲null。
  • ActivityThread mainThread:主線程ActivityThread。
  • LoadedApk packageInfo:解析後的APK對象。
  • IBinder activityToken:Activity Token用來和ActivityManagerService通訊。
  • UserHandle user:用戶信息,通常置爲null。
  • int flags:Context標誌位。
  • Display display:Display對象,描述屏幕相關信息。
  • Configuration overrideConfiguration:應用配置信息。
  • int createDisplayWithId:Display Id。

ContextImpl對象的構建流程以下所示:

  1. 建立默認的應用目錄/data/data/packageName。
  2. 複製mMainThread、mActivityToken、mPackageInfo、mResourcesManager等重要成員變量。
  3. 構建Resouces對象。
  4. 建立Display對象。

理解完Context的建立流程,咱們再來看看它是如何和組件進行綁定的。

三 Context的綁定流程

3.1 Activity與Context的綁定流程

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback, AutofillManager.AutofillClient {
    
        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, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {
            attachBaseContext(context);
            // ...
        }
}
複製代碼

調用ContextWrapper的attachBaseContext()方法將ContextImpl對象賦值給ContextWrapper的成員變量mBase.

3.2 Service與Context的綁定流程

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    
        public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) {
            attachBaseContext(context);
            mThread = thread;           // NOTE: unused - remove?
            mClassName = className;
            mToken = token;
            mApplication = application;
            mActivityManager = (IActivityManager)activityManager;
            mStartCompatibility = getApplicationInfo().targetSdkVersion
                    < Build.VERSION_CODES.ECLAIR;
        }
}
複製代碼

調用ContextWrapper的attachBaseContext()方法將ContextImpl對象賦值給ContextWrapper的成員變量mBase.

3.3 靜態廣播與Context的綁定流程

靜態廣播與Context的綁定與其餘組件不一樣,它是在執行本身onReceive()方法時,經過ContextImpl對象的getReceiverRestrictedContext() 獲取到本身的Context,在傳遞給調用者,以下所示:

receiver.onReceive(context.getReceiverRestrictedContext(),
            data.intent);
複製代碼

上述方法調用ContextImpl的getReceiverRestrictedContext()方法構建了一個ReceiverRestrictedContext對象,ReceiverRestrictedContext 是ContextImpl的內部類,繼承於ContextWrapper,定義了註冊廣播等的一些操做。

class ContextImpl extends Context {
      final Context getReceiverRestrictedContext() {
          if (mReceiverRestrictedContext != null) {
              return mReceiverRestrictedContext;
          }
          return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
      }  
}
複製代碼

3.4 Content Provider與Context的綁定流程

public abstract class ContentProvider implements ComponentCallbacks2 {
    
    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        mNoPerms = testing;

        /* * Only allow it to be set once, so after the content service gives * this to us clients can't change it. */
        if (mContext == null) {
            // 1. 將建立的ContextImpl賦值賦值給Content Provider成員變量mContent。
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                        Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                setAuthorities(info.authority);
            }
            // 2.執行Content Provider的回調方法onCreate()。
            ContentProvider.this.onCreate();
        }
    }
}
複製代碼

ContentProvider與Context的綁定就是將建立的ContextImpl賦值賦值給Content Provider成員變量mContent。

3.5 Application與Context的綁定流程

Application也有一個與ContextImpl對象綁定的過程,以下所示:

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
}
複製代碼

綁定的過程也是調用ContextWrapper的attachBaseContext()方法將ContextImpl對象賦值給ContextWrapper的成員變量mBase.

相關文章
相關標籤/搜索