Android进阶解密读书笔记(五)——理解上下文 Context

Context 的关联类

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

    它的使用场景总的来说分为两大类:

    • 使用 Context 调用方法,比如启动Activity、访问资源、调用系统级服务等

    • 调用方法时传入 Context,比如弹出 Toast、创建 Dialog等

    Activity、Service和Application都间接地继承自 Context,因此我们可以计算出一个应用程序进程中有多少个 Context,这个数量等于Activity和Service的总个数加1,1指的是Application的数量

  2. Context 是一个抽象类,它的内部定义了很多方法和静态常量,它的具体实现类为 ContextImpl,ContextWrapper 则为装饰类,他们两个都继承自 Context。

    ContextImpl 提供了很多功能,但是外界需要使用并扩展 ContextImpl 的功能,因此设计上使用了装饰模式,ContextWrapper 是装饰类,它对 ContextImpl 进行包装,ContextWrapper主要是起了方法传递的作用,ContextWrapper 中几乎所有的方法都是调用 ContextImpl 的相应方法来实现的

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

  3. Context 的关联类使用了装饰模式,主要有一下优点

    • 使用者(比如Service)能够更方便的使用 Context

    • 如果 ContextImpl 发生了变化,它的装饰类 ContextWrapper 不需要做任何修改

    • ContextImpl 的实现不会暴露给使用者,使用者也不必关心 ContextImpl的实现

    • 通过组合而非继承的方式,扩展 ContextImpl 的功能,在运行时选择不同的装饰类,实现不同的功能

Application Context 的创建过程

首先我们从应用程序的启动过程开始着手

  1. ActivityThread 类作为应用程序进程的主线程管理类,它会调用它的内部类 ApplicationThread 的 scheduleLaunchActivity 方法来启动 Activity

  2. 在ApplicationThrad 的 scheduleLaunchActivity 方法中会向 H 类发送 LAUNCH_ACTIVITY类型的消息

    目的是将启动 Activity 的逻辑放在主线程的消息队列中,这样启动 Activity 的逻辑会在主线程中执行

  3. 接着我们查看 H 类的 handleMessage 方法对 LAUNCH_ACTIVITY 类型消息的处理

/*frameworks/base/core/java/android/app/ActivityThread.java*/
private class H extends Handler{
    ...
    public void handlerMessage(Message msg){
        switch(msg){
            case LAUNCH_ACTIVITY:
                //通过 getPackageInfoNoCheck 方法获得 LoadApk 类型对象,并将该对象赋值给 ActivityClientRecord 的成员变量 packageInfo,其中 LoadApk用来描述已加载的APK文件
                r.packageInfo = getPackageInfoNoCheck(r.activtiyInfo.applicationInfo, r.compatInfo);
                //调用ActivityThread 的 handleLaunchActivity
                handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
        }
    }
}

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

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
    ...
    try{
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    }
    ...
    return activity;
}

/*frameworks/base/core/java/android/app/LoadedApk.java*/
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation){
    //如果不为nullze返回mApplication对象,这里看的是第一次启动,所以为null
    if(mApplication != null){
        return mApplication;
    }
    ...
     java.lang.ClassLoader cl = getClassLoader();
    //创建 ContextImpl
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    //创建 Application
    app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
    //将 Application 赋值给 ContextImpl 的 Context 类型的成员变量 mOuterContext,这样 ContextImpl 中也包含了 Application 的引用
    appContext.setOuterContext(app);
    ...
    // 将 Application 赋值给 LoadedApk 的成员变量 mApplication, 用来代表 Application Context
    mApplication = app;
}

//下面我们看一下 Application 是如何创建的
/*frameworks/base/core/java/android/app/Instrumentation.java*/
static public Application newApplication(Class clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
    Application app = (Application) clazz.newInstance();
    //通过反射来创建 Application
    app.attach(context);
    return app;
}

/*Application.java*/
final void attach(Context context){
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

/*ContextWrapper.java*/
protected void attachBaseContext(Context base){
    if(mBase != null){
        throw new IllegalStateException("Base context already set");
    }
    //这个base一路传递过来指的是 ContextImpl,它是 Context 的实现类,将 ContextImpl 赋值给 ContextWrapper 的 Context 类型的成员变量 mBase,而 Application 继承自 ContextWrapper ,同样可以使用 Context 的方法。
    mBase = base;
}

Application 的 attach 方法的作用就是使 Application 可以使用 Context 的方法,这样 Application 才可以用来代表 Application Context

Application Context的获取过程

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

/*ContextWrapper.java*/
public Context getApplicationContext(){
    //mBaser指的是 ContextImpl
    return mBase.getApplicationContext();
}

/*ContextImpl.java*/
//如果 LoadApk 类型的 mPackageInfo 不为 null,则调用LoadApk的getApplication方法,否则调用ActivityThread的getApplicaiont方法
//由于应用程序已经启动,所以 LoadApk 不会为null
public Context getApplicationContext(){
    return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication();
}

/*LoadApk.java*/
//这个 mApplication就是在makeApplication()方法中创建的Application
Application getApplication(){
    return mApplication;
}

Acitivty 的 Context 创建过程

开始的时候和Application的创建过程相似。都是通过 ActivityThread 的内部类 ApplicationThread 来调用 scheduleLaunchActivity 方法来启动,然后在这个方法中通过sendMessage方法向 H 类发送类型为 LAUNCH_ACTIVITY 的消息,H类的handleMessage方法会对该消息进行处理,其中调用了 ActivityThread 的 handleLaunchActivity 方法,而在该方法中又会调用 performLaunchActivity

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

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent){
    ...
    //1.创建 Activity 的 ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);
    java.lang.ClassLoader cl = appContext.getClassLoader();
    //2.创建 Activity 的实例
    activity = mInstrumentation.newActivity(cl, componetn.getClassName(), r.intent);
    ...
    //3.将创建的Activity的实例赋值给 ContextImpl 的成员变量 mOuterContext,这样 ContextImpl 也可以访问 Activity 的变量和方法
    appContext.setOuterContext(activity);
    //4.将ContextImpl传入activity的attach
    activity.attach(appContext, this, ...);
    ...
    if(r.isPersistable()){
        //5.该方法会调用 Activity 的 onCreate 方法
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    }
}

//接下来看一下注释1处的 createBaseContextForActivity()方法(frameworks/base/core/java/android/app/ActivityThread.java)
private ContextImpl createBaseContextForActivity(ActivityClientRecord r){
    ...
    //该方法会调用 ContextImpl 的 createActivityContext 方法来创建 ContextImpl
    ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
    ...
    return appContext;
}

//然后我们再看一下注释4处的 Activity.attach() 方法(Activity.java)
final void attach(Context context, ActivityThread aThread, Instrumentation instr,...){
    
    attachBaseContext(context);//注释1
    //创建 PhoneWindow,代表应用程序窗口。PhoneWindow 在运行中会间接触发很多事件,比如点击、菜单弹出、屏幕焦点变化等事件,这些事件需要转发给与PhoneWindow关联的Activity,转发操作通过Window.Callback接口实现,Activity实现了这个接口
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    //将当前Activity通过Window的setCallback方法传递给PhoneWindow
    mWindow.setCallback(this);
    ...
    //为PhoneWindow设置WindowManager
    mWindow.setWindowManager(
        (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED)!=0);
    
    //获取 WindowManager 并赋值给 Activity 的成员变量 mWindowManager,这样在 Activity中就可以通过 getWindowManager方法来获取WindoManager
    mWindowManager = mWindow.getWindowManager();
    
}

//下面我们来看一下注释一处的attachBaseContext 方法的实现(ContextThemeWrapper.java)
protected void attachBaseContext(Context newBase){
    //父类是ContextWrapper
    super.attachBaseContext(newBase);
}

//ContextWrapper.java
protected void attachBaseContext(Context base){
    if(mBase != null){
        throw new IllegalStateException("Base context already set");
    }
    //base指的是一路传递过来的 Activity 的 ContextImpl,将它赋值给 ContextWrapper的成员变量 mBase,当我们调用ContextWrapper中的方法时实际上就是调用的ContextImpl中的方法
    mBase = base;
}

总结一下,在启动Activity的过程中创建 ContextImpl,并赋值给 ContextWrapper 的成员变量 mBase。Activity 继承自 ContextWrapper 的子类 ContextThemeWrapper,这样Activity中就可以使用Context中定义的方法了

Service 的 Context 创建过程

Service的Context创建过程与Activity的Context创建过程相似,是在 Service 的启动过程中被创建的。ActivityThread 的内部类 ApplicationThread 会调用 scheduleCreateService 方法来启动 Service,在这个方法中会使用sendMessage方法向 H 类发送 CREATE_SERVICE 类型的消息,H类的 handleMessage 方法会对 CREATE_SERVICE 类型的消息进行处理,其中会调用 ActivityThread 的 handleCreateSerice方法

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

private void handleCreateService(CreateServiceData data){
    ...
    //通过 ContextImpl 的createAppContext 方法创建 ContextImpl
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    
    //将该 ContextImpl 传入 service 的 attach 方法中
    service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
}

/*Service.java*/
public final void attach(Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager){
    
    //调用 ContextWrapper 的 attachBaseContext 方法
    attachBaseContext(context);
}

//ContextWrapper.java
protected void attachBaseContext(Context base){
    if(mBase != null){
        throw new IllegalStateException("Base context already set");
    }
    //base指的是一路传递过来的 Activity 的 ContextImpl,将它赋值给 ContextWrapper的成员变量 mBase,当我们调用ContextWrapper中的方法时实际上就是调用的ContextImpl中的方法
    mBase = base;
}

Service继承自ContextWrapper,同样可以使用Context方法

你可能感兴趣的:(Android进阶解密读书笔记,android,java)