解析Android中的Context

   日期:2020-07-10     浏览:89    评论:0    
核心提示:理解上下文 Context Context 也就是上下文对象,是 Android 常用的类,但是对于 Context ,很多人都停留在会用的阶段,本文将带领大家从源码的角度来分析 Context ,从而更加深入地理解它。本文基于Android8.1.0系统分析Context。 1.Context 的关联类 Context 意为上下文,是 个应用程序环境信息的接口。 在开发中我们经常使用 Context ,它的使用场景总的来...

理解上下文 Context   

       Context 也就是上下文对象,是 Android 常用的类,但是对于 Context ,很多人都停留在会用的阶段,本文将带领大家从源码的角度来分析 Context ,从而更加深入地理解它。 本文基于Android8.1.0系统分析Context。    

    1. Context 的关联类   

       Context 意为上下文,是一个应用程序环境信息的接口。

       在开发中我们经常使用 Context ,它的使用场景总的来说分为两大类,它们分别是: 

  • 使用 Context 调用方怯,比如启动 Activity 、访问资糖、调用系统级服务等。
  • 调用方怯时传入 Context 比如弹出 Toast 、创建 Dialog 等。
       Activity、 Service、 Application 都间接地继承自 Context ,因此我们可以计算出一个应用程序进程中有多少个 Context ,这个数 量等于 Ac tivity、 Service 的总个数加1  , 指的是 Application 的数量。       Context 个抽象类,它的内部定义了很多方法以及静态常量  ,它的具体实现类为 Contextlmpl 。和 Context 相关联的类,除了 Contextlmpl ,还有 Context Wrapper、ContextThemeWrapp 和  Activity 等,如图 所示:

       从上图可以看出,Contextlmpl 和 ContextWrapper 继承自 Context,ContextWrapper 内部包含 Context 类型的 mBase 对象, mBase 具体指向 Contextlmpl。Contextlmpl 提供了很多功能,但是外界需要使用并拓展 Contextlmpl 的功能,因此设计上使用了装饰模式, ContextWrapper 是装饰类,它对 Contextlmpl 进行包装, ContextWrapper主要是起了方法传递的作用, ContextWrapper 中几乎所有的方法都是调用 Contextlmpl 的相应方法来实现的。 ContextThemeWrapper、Service、Application 都继承自 ContextWrapper,这样它们都可以通过 mBase 来使用 Context 的方法,同时它们也是装饰类,在 ContextWrapper的基础上又添加了不同的功能。 ContextThemeWrapper 中包含和主题相关的方法(比如getTheme 方法),因此,需要主题的 Activity 继承 ContextThemeWrapper ,而不需要主题的Service 继承 ContextWrapper。

       Context 的关联类采用了装饰者模式,主要有以下的优点:

  •  使用者(比如 Service )能够更方便地使用 Context。
  •  如果 Contextlmpl 发生了变化,它的装饰类 ContextWrapper 不需要做任何修改。
  •  Contextlmpl 的实现不会暴露给使用者,使用者也不必关心 Contextlmpl 的实现。
  •  通过组合而非继承的方式,拓展 Contextlmpl 功能,在运行时选择不同的装饰类, 实现不同的功能
             为了更好地理解 Context 的关联类的设计理念,就需要理解 App lication 、 Activity 、 Service 的 Context 的创建过程,下面分别对它们进行介绍。

 

     2. Application Context 的创建过程

       我们通过调用 getApplicationContext 来获取应用程序全局的 Application Context ,那么 Application Context 是如何创建的呢?在一 个应用程序启动完成后,应用程序就会有一 个全局的 Application Context ,那么我们就从应用程序启动过程开始着手。         ActivityThread 类作为应用程序进程的 主线程管理类 ,它 会调 用它的内部类  A pplication Thread  的  scheduleLaunchActivity 方法来启动 Activity ,如下所示:  

frameworks/base/core/java/android/app/ActivityThread.java

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
    }
       在Application Thread 的  scheduleLaunchActivity 方法 中向 H  类发送 LAUNCH_AC TIVITY 类型的消息,目的是将启动 Acti vity 的逻辑放在主线程的消息队列中,这样启动 Ac tivity 的 逻辑会在主线程中执行。我们接 着查看 H  类的 handleMessage 方法对 LAUNCH_ ACTMTY 类型 的消息的处理,代码如下所示:   frameworks/base/core/java/android/app/ActivityThread.java  
private class H extends Handler {      
       ... 
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj; // ... 1
 
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo); // ... 2
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); // ... 3
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;                  
                ...                
            }
            Object obj = msg.obj;
            if (obj instanceof SomeArgs) {
                ((SomeArgs) obj).recycle();
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
        }
    }

       H继承自Handler,在注释1处将传过来的 msg 的成员变量 obj 转换为 ActivityClientRecord 。在注释2处通过 getPackagelnfoNoCheck 方法获得 LoadedApk 类型的对象并赋值给 ActivityClientRecord 的成员变量packagelnfo 。应用程序进程要启动 Activity 需要将该 Activity 所属的 APK 加载进来,而 LoadedApk 就是用来描述己加载的 APK 文件的。在注释3处调用 handleLaunchActivity 方法,代码如下所示:
frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {       
        ... 
        // 启动Activity
        Activity a = performLaunchActivity(r, customIntent); // ... 1
 
        ...
    }

       在handleLaunchActivity 方法中调用了 ActivityThread 的 performLaunchActivity 方法,代码如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        try {
            // 创建Application
            Application app = r.packageInfo.makeApplication(false, mInstrumentation); 
            ...
        } 
        ...
        return activity;
    }
       在performLaunchActivity 方法 中有很 多重要 的逻 辑,这里只保留了和  Application Context 相关的逻辑,想要了解更多 perfomL aunchActivity 方法中的逻辑请查看“解析Activity的启动过程 ”的 内容。 ActivityClientRecord 的成员变 packagelnfo 是 LoadedApk 类型的,我 们接 着来查看 LoadedApk 的 makeApplication 方法 ,代码如下所示:   frameworks/base/core/java/android/app/LoadedApk.java  

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) { // ... 1
            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 {
            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);
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); // ... 2
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext); // ... 3
            appContext.setOuterContext(app); // ... 4
        } 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);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app; // ... 5
        ...
        return app;
    }
       在注释1 处如果 mApplication 不为 null 则返回 mApplication ,这里假设是第一 次启动 应用程序,因此 mApp lication 为  null 。在注释2 处通过 Con textlmpl 的  createAppContext 方法 来创建 Contextlmpl 。注释3 处的代码用来创建 Application ,在 Instrumentation 的  new Application 方怯中传入了 ClassLoader 类型的对象以及注释2 处创建的 Contextlmpl 。在注释4处将 Application 贼值给 Contextlmpl 的  Context 类型的成员变量  mOuterContext ,这 样 Contextlmpl 中也包含了 Application 的引用。 在注释5处将 Application 赋值给 LoadedApk 的成员变 mApplication ,这个 mApplication 是  Application 类型的对象,它用来代表 Application Context ,在 Application Context 的获取过程中我们会再次提到 mApplication 。下面来 查看 注释3 处的 Application 是如何创建的, Instrumentation 的  new Application 方法代码 如下所示:   frameworks/base/core/java/android/app/lnstrumentation.java  
    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance(); // ... 1
        app.attach(context); // ... 2
        return app;
    }
       Instrumentation 中有两个  new Application 重载方法,最终会调 用上面这个重载方法。注释1 处通过反射来创 Application ,在注释2处调用了 Application 的  attach 方法, Contextimpl 传进去, 最后 返回该 Application , Application 的  attach 方法如下所示:   frameworks/base/core/java/android/app/Application.java  
     final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

       在attach方法中调用了attachBaseContext方法,它在Application的父类ContextWrapper中实现,代码如下所示:

frameworks/base/core/java/android/content/ContextWrapper.java
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
       这个 base 一路传递过来指的是 Contextimpl ,它是 Context 的实现 类, Contextimpl 赋值给 Context Wrapper 的  Context 类型的成员变 mBase ,这样在 Context Wrapper 中就可以使用 Context 的方法,而 Application 继承自 Context Wrapper ,同样可以使用 Context 的方法。 Application 的  attach 方法 的作用就是使 Application 可以使用 Context 的方法,这样 Application 才可以用来代表 Application Context。        Application Context 的创建过程就讲到这里,接下来 我们 来分析A pplication Context 的 获取过程。  

    3. Application Context 的获取过程

       当我们熟知了 Application Context 的创建过程之后,那么它的获取过程会非常好理解。 我们通过调用 getApplicationContext 方法来获得 Application Context, getApplicationContext 方法在 Context Wrapper 中实现,代码如下所示:   frameworks/base/core/java/android/content/ContextWrapper.java  
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }

       在getApplicationContext 方法中,mBase指的是ContextImpl,接下来查看ContextImpl的getApplicationContext 方法,代码如下所示:

frameworks/base/core/java/android/app/Contextlmpl.java

    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
       如果 LoadedApk 类型的 mPackagelnfo 不为 null ,则调用 LoadedApk 的  getApplication 方法,否则调用 ActivityThread 的 getApplication 方法 。由于应用程序这时已经启动,因此 LoadedApk不会为 null ,则 会调用 LoadedApk 的  getApplication 方法 ,代码如下所示:   frameworks/base/core/java/android/app/LoadedApk.java
    Application getApplication() {
        return mApplication;
    }
       这里的 mApplication 我们应该很熟悉,它在上文 LoadedApk 的  makeApplication 方法 注释5处被赋值。这样我们通过 getAppl icationContext 方法 就获取到了 Application Context 。    

     4. Activity的Context 创建过程

       想要在 Activity 中使用 Context 提供的方法,务必要先创建 Context 。 Activity 的  Context 会在 Activity 的启动过程中被创建,在 “解析Activity的启动过程 ”中讲到了 ActivityThread 启动 Activity 的过程,我们就从这里开始分析。                ActivityThread 类作为应用程序进程的 主线程管理类 ,它 会调 用它的内部类  A pplication Thread  的  scheduleLaunchActivity 方法来启动 Activity ,如下所示:  

frameworks/base/core/java/android/app/ActivityThread.java

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
    }
      scheduleLaunchActivity 方法将启动 Activity 的参数封装成 ActivityClientRecord   , sendMessage 方法向 H  类发 送类型为 LAUNCH_ ACTIVITY 的消 息, 并将 ActivityC lientR ecord 传递过去。 sendMessage 方法 的目的是将启动  Activity 的逻辑放 在主 线程的消息队列中,这样启动 Activity 的逻辑就会 在主线 程中执行 。H 类的 h and leMessage 方法会对 LAUNCH_ACTIVITY 类型的消息进行处理,其中调用了 Activity Thr ead 的 ha ndl eLaunchActi vity 方法,而在 handleLaunchActivity  方法中又 调用了 ActivityThread 的  perfomLa un chActi vity 方法,这一过程在第2 节已经 讲过了,我们直 接来 查看 ActivityThread 的   perforrnLau nchActi vity 方法,代码如下所示:   frameworks/base/core/java/android/app/ActivityThread.java

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...

        ContextImpl appContext = createBaseContextForActivity(r); // ... 1
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent); // ... 2
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }

        try {
            ...

            if (activity != null) {
                ...
                appContext.setOuterContext(activity); // ... 3
                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, r.configCallback); // ... 4

                ...

                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); // ... 5
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
            }
            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;
    }
       在 perfomLaunchActivity 方法中有很多重 要的逻辑,这里 只保留了和  Activity 的  Context 相关 的逻辑 。 在注释2 处用来创建 Activity 的实例,  在注释1 处通过 createBaseContextForActivity 方法来创建 Activity 的  Contextlmpl ,并将 Contextlmpl 传入 注释 4 处的 activity 的  attach 方法中。在注释3处调用了 Contextlmpl 的  setOuterContext 方法 ,将此前创建的 Activity 实例赋值给 Contextlmpl 的成员变 mOuterContext ,这样 Contextlmpl 也可以访问 Activity 的变量 和方法 。在 注释5 处 m Instrumentation 的 callActivityOnCre ate 方法中会 调用 Activity 的  onCreate 方法。我们 查看 注释1 处的 createBaseContextForActivity 方法,代码如下所示:   frameworks/base/core/java/android/app/ActivityThread.java  

    private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        ...
        return appContext;
    }
       在 createBaseContextForActivity 方法中会调用 Contextlmpl 的  createActivityContext 方法来创建 Contextlmpl 。 我们回到 ActivityThread 的  perforrnLau nchActi vity 方法 查看 注释4 处的 Activity 的  attach 方法 ,代码如下所示:   frameworks/base/core/java/android/app/Activity.java
   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); // ... 1

        mFragments.attachHost(null );

        mWindow = new PhoneWindow(this, window, activityConfigCallback); // ... 2
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this); // ... 3
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ...
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); // ... 4
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager(); // ... 5
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }
       在注释2处创建 Phone Window , 它代表应用程 序窗 口。 Phone Window 在 运行中会 间接触发很 多事 件,比如点击、菜 单弹出、屏幕 焦点变化等事件,这些事件要转发给与 PhoneWindow 关联的 Activity ,转发操作通过 Window. Callback 接口实现, Actvity 实现了这个接口 。在注释3 处将当前  Activity 通过  Window 的  setCallback 方法 传递给 Phone Window 。在注释4处为 Phone Window 设置 Window Manager ,在注释5 处获取 Window Manager 并 赋值 Activity 的成员变 m Window Manager ,这样在 Activity 中就可以通过 get Window Manager 方法来获取 Window Manager 。注释1 处的 attachBaseContext 方法 ContextTheme Wrapper 中实现,代码如下所示:   frameworks/base/core/java/android/view/ContextThemeWrappe.java
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }
       在attachBaseContext 方法中接着 调用 ContextThemeWrapper 的父类 ContextWrapper 的 attachBaseContext 方法,代码如下所示:   frameworks/base/core/java/android/content/ContextWrapper.java  
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base; // ... 1
    }
       注释1 处的 base 指的是一 路传递过来的 Activity 的  Contextlmpl ,将它赋值给 ContextWrapper 的成员变 mBase 。这样 ContextWrapper 的功能就可以交由  Contextlmpl  来处理。 Activ ity 的  Conte xt 创建过程就讲到这里。总结一 下,在启动 Activity 的过程中创建 Contextlmpl ,并赋值给 Context Wrapper 的成员变 mBase 。 Activity 继承自 Context Wrapper 的子类 ContextTheme Wrapper ,这样在 A ctivity 中就可以使用 Context 中 定义的方法了。
 

    5. Service的Context 创建过程

       Service 的  Context 创建过程与 Activity 的  Context 创建过 程类 似, 是在 Service 的启动过程中被创建的。在 解析Service的启动过程 ”中讲到了 Activi tyThread 启动  Service 的过程,我们从这里开始分析。 ActivityThread 的内部类 Application Thread 调用 scheduleCreateService 方法 启动 Service,代码如下所示:   frameworks/base/core/java/android/app/ActivityThread.java  
        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }
       sendMessage 方法向 H 类 发送 CREATE_ SERVICE 类型 的消息, H  类的 ha ndl eMessage 方法会对 CREATE_ SERVICE 类型的消息进行处理,其中调用了  ActivityThread 的 handleCreateService  方法,代码如下所示:   frameworks/base/core/java/android/app/ActivityThread.java
 private void handleCreateService(CreateServiceData data) {
        ...
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
 
            // 创建Service的上下文环境ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo); // ... 1
            context.setOuterContext(service);
 
            Application app = packageInfo.makeApplication(false, mInstrumentation);
 
            // 初始化Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService()); // ... 2
            service.onCreate(); 
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().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);
            }
        }
    }
       在注释1处通过ContextImpl 的 createAppContext 方法  创建了 ContextImpl 的对象context ,并将该context对象传 入注释2处 service 的 attach  方法中,代码如下所示   frameworks/base/core/java/android/app/Service.java
    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context); // ... 1
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }
       在注释1 处调用了 Context Wrapper 的 attachBaseContext 方法 ,代码如下所示:   frameworks/base/core/java/android/content/ContextWrapper.java  
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base; // ... 1
    }
       注释1处的 base是 一路传递过来的  Contextimpl ,将 Contextlmpl 赋值给 Context Wrapper 的 Context 类型的成员变 mBase , 这样在 Context Wrapper 中就可以使用 Context 的方法 Service 继承自 Context Wrapper ,同样可以使用 Context 的方法。  
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服