5.理解上下文Context

Context的关联类

这篇文章只是对刘望舒大佬书籍的摘抄,适合复习用,没看过的请先看大佬的原书
下面是大佬博客的链接Android进阶三部曲 第二部《Android进阶解密》


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

Context的使用场景分为两个大类

  • 使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等
  • 调用方法时传入Context,比如弹出Toast,创建Dialog等

由于Activity,Service和Application都间接继承自Context,所以一个应用程序进程中Context的数量等于Activity和Service的总个数+1(Application)

Context是一个抽象类,它的内部定义了很多方法以及静态常量,它的具体实现为ContextImpl。

和Context相关联的类,除了ContextImpl还有ContextWrapper、ContextThemeWrapper和Activity等,他们的关系如下图

5.理解上下文Context_第1张图片

ContextImpl和ContextWrapper继承自Context,ContextWrapper和ContextImpl是依赖关系,ContextWrapper依赖ContextImpl的实现。

ContextWrapper内部包含Context类型的mBase对象,mBase具体指向ContextImpl.

ContextWrapper使用了装饰模式,它对ContextImpl进行了包装,ContextWrapper主要是起了方法传递的作用。ContextWrapper中几乎所有方法都是调用ContextImpl相应方法来现实的。

ContextThemeWrapper、Service、和Application都继承自ContextWrapper,这样他们都可以通过mBase来使用Context的的方法。同时它们也是装饰类,在ContextWrapper的基础上添加了不同的功能。ContextThemeWrapper中包含和主题相关的方法。因此需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service继承ContextWrapper

Context的关联类采用装饰模式的主要优点

  • 使用者可以更方便的使用Context
  • 如果ContextImpl发生了变化,它的装饰类ContextWrapper不需要做任何修改
  • ContextImpl的实现不会暴露给使用者,使用者也不必关心ContextImpl的实现
  • 通过组合而非继承的方式,拓展ContextImpl的功能,在运行时选择不同的装饰类,实现不同的功能

了解Application、Activity、Service的Context的创建过程可以更好的理解Context关联类的设计理念

Application Context的创建过程

Application Context的创建过程时序图如下

5.理解上下文Context_第2张图片

首先是ActivityThread类的 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;
  ...
  updatePendingConfiguration(curConfig);
  sendMessage(H.LAUNCH_ACTIVITY, r);
}

这里通过handler发送消息过去最后调用了handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
  ...
    Activity a = performLaunchActivity(r, customIntent);
  ...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
  try {
    //调用LoadedApk的makeApplication方法
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
  ...
  }
  ...
}

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

public Application makeApplication(boolean forceDefaultAppClass,
                                   Instrumentation instrumentation) {
  ...
  try {
    java.lang.ClassLoader cl = getClassLoader();
    ...
    //创建ContextImpl
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    //使用Instrumentation创建Application
    app = mActivityThread.mInstrumentation.newApplication(
      cl, appClass, appContext);
    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);
    }
  }
  mActivityThread.mAllApplications.add(app);
  //将app赋值mApplication属性
  mApplication = app;
  ...
  return app;
}

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

public Application newApplication(ClassLoader cl, String className, Context context)
  throws InstantiationException, IllegalAccessException,ClassNotFoundException {
  return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
  throws InstantiationException, IllegalAccessException,ClassNotFoundException {
  Application app = (Application)clazz.newInstance();
  //调用attach方法,并将ContextImpl的conttext传进去
  app.attach(context);
  return app;
}

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

final void attach(Context context) {
  //调用父类ContextWrapper的方法attachBaseContext
  attachBaseContext(context);
  mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

/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;
}

最终将ContextImpl类型的context传给到了ContextWrapper的mBase属性

Application Context的获取过程

我们通过调用getApplicationContext方法来获得 Application Context,getApplicationContext 方法在 ContextWrapper中实现

/frameworks/base/core/java/android/content/ContextWrapper.java

public Context getApplicationContext() {
  //调用ContextImpl的getApplicationContext
  return mBase.getApplicationContext();
}

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

public Context getApplicationContext() {
  //如果LoadedApk类型的mPackageInfo不为null,则调用其getApplication方法,否则调用ActivityThread的getApplication方法
  return (mPackageInfo != null) ?
    mPackageInfo.getApplication() : mMainThread.getApplication();
}

由于进程已经启动,因此LoadedApk不会为null,所以调用了LoadedApk的getApplication方法

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

Application getApplication() {
  return mApplication;
}

这里mApplication的赋值是在上面LoadedApk的makeApplication方法里处理的

Activity 的 Context 创建过程

Activity的Context会在Activity的启动过程中被创建。Activity的Context创建过程的时序图如下

5.理解上下文Context_第3张图片

我们从performLaunchActivity开始看起

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

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
  //1.创建Activity的ContextImpl
  ContextImpl appContext = createBaseContextForActivity(r);
  Activity activity = null;
  try {
    java.lang.ClassLoader cl = appContext.getClassLoader();
    //2.创建Activity的实例
    activity = mInstrumentation.newActivity(
      cl, component.getClassName(), r.intent);
    ...
  } catch (Exception e) {
    ...
  }
  try {
    ...
    if (activity != null) {
      ...
      //3.将创建的Activity实例赋值给ContextImpl的成员变量mOuterContext
      appContext.setOuterContext(activity);
      //4.将appContext传入到attach方法中
      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);

      ...
      if (r.isPersistable()) {
        //5.调用Activity的onCreate方法
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
      } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
      }
      ...
    r.paused = true;
    mActivities.put(r.token, r);
  } catch (SuperNotCalledException e) {
   ...
  }
  return activity;
}

注释1处的createBaseContextForActivity会创建Activity需要的Context

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
  ...
  //调用createActivityContext创建ContextImpl
  ContextImpl appContext = ContextImpl.createActivityContext(
    this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
	...
  return appContext;
}

注释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) {
  //1.调用ContextWrapper的attachBaseContext方法,给mBase赋值
  attachBaseContext(context);
  mFragments.attachHost(null /*parent*/);
  //2.创建PhoneWindow的,代表应用程序窗口。会触发点击、菜单、屏幕焦点变化等事件
  mWindow = new PhoneWindow(this, window, activityConfigCallback);
  mWindow.setWindowControllerCallback(this);
  //3.设置PhoneWindow的事件回调,由此各种事件转发给了Activity
  mWindow.setCallback(this);
  mWindow.setOnWindowDismissedCallback(this);
  mWindow.getLayoutInflater().setPrivateFactory(this);
  ...
  //4.给PhoneWindow设置WindowManager
  mWindow.setWindowManager(
    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
    mToken, mComponent.flattenToString(),
    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
  if (mParent != null) {
    mWindow.setContainer(mParent.getWindow());
  }
  //5.获取PhoneWindow的WindowManager,并赋值非Activity的成员变量mWindowManager
  mWindowManager = mWindow.getWindowManager();
  mCurrentConfig = config;

  mWindow.setColorMode(info.colorMode);
}

在Activity的attach方法里调用attachBaseContext给祖父类ContextWrapper的mBase成员变量赋值

Service 的 Context 创建过程

Service的Context创建也是在Service的启动过程中被创建的。Service的Context创建过程时序图类似Activity创建的时序图

首先是ActivityThread的handleCreateService方法

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

private void handleCreateService(CreateServiceData data) {
  ...
  try {
    ...
    //1.通过调用ContextImpl的createAppContext方法创建ContextImpl
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    context.setOuterContext(service);
    Application app = packageInfo.makeApplication(false, mInstrumentation);
    //2.将ContextImpl传入到attach方法中
    service.attach(context, this, data.info.name, data.token, app,
                   ActivityManager.getService());
    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) {
    ...
  }
}

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

public final void attach(
  Context context,
  ActivityThread thread, String className, IBinder token,
  Application application, Object activityManager) {
  //1.调用attachBaseContext给mBase赋值
  attachBaseContext(context);
  mThread = thread;           
  mClassName = className;
  mToken = token;
  mApplication = application;
  mActivityManager = (IActivityManager)activityManager;
  mStartCompatibility = getApplicationInfo().targetSdkVersion
    < Build.VERSION_CODES.ECLAIR;
}

你可能感兴趣的:(Android进阶解密笔记,android,系统源码,Context)