Android深入理解Context(二)Activity和Service的Context创建过程

刘望舒
• 阅读 1668
  • Android框架层
  • Android深入理解Context categories:
  • Android框架层

本文首发于微信公众号「刘望舒」

前言

上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程。需要注意的是,本篇的知识点会和深入理解四大组件系列的部分文章的知识点相重合。

1.Activity的Context创建过程

当我们在Activity中调用startActivity方法时,其实调用的是Context的startActivity方法,如果想要在Activity中使用Context提供的方法,务必要先创建Context。Activity的Context会在Activity的启动过程中被创建,在Android深入四大组件(一)应用程序启动过程(后篇)的第二小节中,讲到了ActivityThread启动Activity的过程,我们就从这里开始分析。 ActivityThread是应用程序进程的核心类,它的内部类ApplicationThread会调用scheduleLaunchActivity方法来启动Activity,scheduleLaunchActivity方法如下所示。

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

@Override
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;
        ...
        sendMessage(H.LAUNCH_ACTIVITY, r);
}

scheduleLaunchActivity方法会将启动Activity的参数封装成ActivityClientRecord ,sendMessage方法向H类发送类型为LAUNCH_ACTIVITY的消息,并将ActivityClientRecord 传递过去。sendMessage方法的目的是将启动Activity的逻辑放在主线程中的消息队列中,这样启动Activity的逻辑就会在主线程中执行。 H类的handleMessage方法中会对LAUNCH_ACTIVITY类型的消息进行处理,其中调用了handleLaunchActivity方法,而handleLaunchActivity方法中又调用performLaunchActivity方法,这一过程在Android深入理解Context(一)Context关联类和Application Context创建过程已经讲过了,我们来查看performLaunchActivity方法。 frameworks/base/core/java/android/app/ActivityThread.java

  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);//1
             ...
            }
        } catch (Exception e) {
           ...
        }

        try {
          ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);//2
                ...
                /**
                *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); 
                ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//4
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
               ...
        }

        return activity;
    }

performLaunchActivity方法中有很多重要的逻辑,这里只保留了Activity的Context相关的逻辑。在注释1处用来创建Activity的实例。注释2处通过createBaseContextForActivity方法用来创建Activity的ContextImpl,并将ContextImpl传入注释3处的activity的attach方法中。在注释4处Instrumentation的callActivityOnCreate方法中会调用Activity的onCreate方法。 我们先来查看注释2出的createBaseContextForActivity方法: frameworks/base/core/java/android/app/ActivityThread.java

  private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);//1
        appContext.setOuterContext(activity);//2
        Context baseContext = appContext;
        ...
        return baseContext;
    }

在注释1处调用ContextImpl的createActivityContext方法来创建ContextImpl,注释2处调用了ContextImpl的setOuterContext方法,将此前创建的Activity 实例赋值给ContextImpl的成员变量mOuterContext,这样ContextImpl也可以访问Activity的变量和方法。 我们再回到ActivityThread的performLaunchActivity方法,查看注释3处的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) {
        attachBaseContext(context);//1
        mFragments.attachHost(null /*parent*/);
        mWindow = new PhoneWindow(this, window);//2
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);//3
        mWindow.setOnWindowDismissedCallback(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;
    }

在注释2处创建PhoneWindow,它代表应用程序窗口。PhoneWindow在运行中会间接触发很多事件,比如点击事件、菜单弹出、屏幕焦点变化等事件,这些事件需要转发给与PhoneWindow关联的Actvity,转发操作通过Window.Callback接口实现,Actvity实现了这个接口,在注释3处将当前Activity通过Window的setCallback方法传递给PhoneWindow。 注释4处给PhoneWindow设置WindowManager,并在注释5处获取WindowManager并赋值给Activity的成员变量mWindowManager ,这样在Activity中就可以通过getWindowManager方法来获取WindowManager。 在注释1处调用了ContextThemeWrapper的attachBaseContext方法,如下所示。

frameworks/base/core/java/android/view/ContextThemeWrapper.java

@Override
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的ContextImpl,将它赋值给ContextWrapper的成员变量mBase。这样ContextWrapper的功能就可以交由ContextImpl处理,举个例子: frameworks/base/core/java/android/content/ContextWrapper.java

@Override
public Resources.Theme getTheme() {
    return mBase.getTheme();
}

当我们调用ContextWrapper的getTheme方法,其实就是调用的ContextImpl的getTheme方法。 Activity的Context创建过程就讲到这里。 总结一下,在启动Activity的过程中创建ContextImpl,并赋值给ContextWrapper的成员变量mBase中。Activity继承自ContextWrapper的子类ContextThemeWrapper,这样在Activity中就可以使用ContextImpl了。 下面给出ActivityThread到ContextWrapper的调用时序图。 Android深入理解Context(二)Activity和Service的Context创建过程

2.Service的Context创建过程

Service的Context创建过程与Activity的Context创建过程类似,也是在Service的启动过程中被创建。Service的启动过程这篇文章的第二节中讲到了ActivityThread启动Service的过程,我们从这里开始分析。 ActivityThread的内部类ApplicationThread会调用scheduleCreateService方法来启动Service,如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

public final void scheduleCreateService(IBinder token,
         ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
     ...
     sendMessage(H.CREATE_SERVICE, s);
 }

sendMessage方法向H类发送CREATE_SERVICE类型的消息,H类的handleMessage方法中会对CREATE_SERVICE类型的消息进行处理,其中调用了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);
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//1
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());//2
            service.onCreate();
          ...
        } catch (Exception e) {
          ... 
        }
    }

在注释1处创建了ContextImpl ,并将该ContextImpl传入注释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处调用了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;
}

attachBaseContext方法在前文已经讲过,这里不再赘述。 Service的Context创建过程就讲解到这里,由于它和Activity的Context创建过程类似,因此,可以参考前文给出的ActivityThread到ContextWrapper的调用时序图。

点赞
收藏
评论区
推荐文章
刘望舒 刘望舒
3年前
Android深入理解JNI(二)类型转换、方法签名和JNIEnv
Android框架层Android深入理解JNIAndroid框架层本文首发于微信公众号「刘望舒」前言上一篇文章介绍了JNI的基本原理和注册,这一篇接着带领大家来学习JNI的数据类型转换、方法签名和JNIEnv。<!more1.数据类型的转换首先给出上一篇文章中androidmediaMediaRecorder.cpp中的androidmediaMe
刘望舒 刘望舒
3年前
Android深入理解Context(一)Context关联类和Application Context创建过程
Android框架层Android深入理解Contextcategories:Android框架层本文首发于微信公众号「刘望舒」前言Context也就是上下文对象,是Android较为常用的类,但是对于Context,很多人都停留在会用的阶段,这个系列会带大家从源码角度来分析Context,从而更加深入的理解它。<!more1.Context概述Co
刘望舒 刘望舒
3年前
Android输入系统(二)IMS的启动过程和输入事件的处理
Android框架层Android输入系统Android框架层本文首发于微信公众号「刘望舒」基于Android8.1前言在上一篇文章中,我们学习了IMS的诞生(创建),IMS创建后还会进行启动,这篇文章我们来学习IMS的启动过程和输入事件的处理。1.IMS的启动过程IMS的创建在SystemServer的startOtherServices方法中,
刘望舒 刘望舒
3年前
Android深入四大组件(一)应用程序启动过程(前篇)
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「后厂技术官」前言在此前的文章中,我讲过了Android系统启动流程和Android应用进程启动过程,这一篇顺理成章来学习Android7.0的应用程序的启动过程。分析应用程序的启动过程其实就是分析根Activity的启动过程。<!more1
刘望舒 刘望舒
3年前
Android深入四大组件(四)广播的注册、发送和接收过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言我们接着来学习Android四大组件中的BroadcastReceiver,广播主要就是分为注册、接收和发送过程。1.广播的注册过程BroadcastReceiver的注册分为两种,分别是静态注册和动态注册,静态注册在应用安装时由
刘望舒 刘望舒
3年前
Android解析ActivityManagerService(二)ActivityTask和Activity栈管理
Android框架层Android系统服务ActivityManagerServiceAndroid框架层本文首发于微信公众号「刘望舒」前言关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够。这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理。1.ActivityStackActivi
刘望舒 刘望舒
3年前
Android解析WindowManager(二)Window的属性
Android框架层Android系统服务WindowManagercategories:Android框架层本文首发于微信公众号「刘望舒」前言在上一篇文章我们学习了WindowManager体系,了解了Window和WindowManager之间的关系,这一篇我们接着来学习Window的属性。<!more1.概述上一篇文章中我们讲过了Window
刘望舒 刘望舒
3年前
Android深入四大组件(三)Service的绑定过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言我们可以通过调用Context的startService来启动Service,也可以通过Context的bindService来绑定Service,建议阅读此篇文章前请阅读这篇文章,知识点重叠的部分,本篇文章将不再赘述。<!more
刘望舒 刘望舒
3年前
Android深入四大组件(五)Content Provider的启动过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言ContentProvider做为四大组件之一,通常情况下并没有其他的组件使用频繁,但这不能作为我们不去深入学习它的理由。关于ContentProvider一篇文章是写不完的,这一篇文章先来介绍它的启动过程。<!more1.q
刘望舒 刘望舒
3年前
Android深入四大组件(二)Service的启动过程
Android框架层Android深入四大组件categories:Android框架层本文首发于微信公众号「刘望舒」前言此前我用较长的篇幅来介绍Android应用程序的启动过程(根Activity的启动过程),这一篇我们接着来分析Service的启动过程。建议阅读此篇文章前,请先阅读和这两篇文章。<!more1.ContextImpl到Activi