Context 和组件关系


一、Activity、Application 和 Service

三者经常和 Context 打交道,它们都和 Context 有关联。

组件和 Context 的关系

装饰者模式,都继承 ContextWrapper 类,该类提供 attachBaseContext() 方法赋值内部被装饰者具体对象,基类 Context,真实类 ContextImpl。

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;//ContextImpl对象。
}

在 Activity 类的 attach() 方法,ContextImpl 类提供静态方法创建实例。

static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread, packageInfo, null, null, false,
                null, overrideConfiguration, displayId);
}

在 Service 类的 attach() 方法,创建 ContextImpl 实例的静态方法与前者不同。

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread,
                packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
}

创建 Application 内部 ContextImpl 实例的方法和 Service 一样,Application 的attach()方法,设置内部 Context。

ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
appContext.setOuterContext(app);

ContextImpl类的setOuterContext()方法,设置外部引用它的Context。

二、ContentProvider和BroadcastReceiver

ContentProvider不继承Context,构造方法创建对象时,入参初始化内部Context。

public ContentProvider(
            Context context,
            String readPermission,
            String writePermission,
            PathPermission[] pathPermissions) {
    mContext = context;
    mReadPermission = readPermission;
    mWritePermission = writePermission;
    mPathPermissions = pathPermissions;
}

BroadcastReceiver不继承Context,内部无Context对象,在onReceive()方法时传入,该方法可以使用Context功能。

public abstract void onReceive(Context context, Intent intent);

三、常用方法

1,getApplicationContext()方法

在Activity,Service和Application,该方法用于获取Context。

@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}

父类ContextWrapper提供方法,真实类ContextImpl的实现方法(Context的抽象方法)。

@Override
public Context getApplicationContext() {
    return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
}

从LoadedApk类或从ActivityThread类获取,LoadedApk在makeApplication()方法赋值,ActivityThread在handleBindApplication()方法初始化,也是通过LoadedApk类的makeApplication()方法创建。

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;

因此,getApplicationContext()方法,本质是从ContextImpl对象中获取全局Application。

2,getApplication()方法
在Activity和Service,返回内部Application对象,attach()方法时初始化,全局对象。

四、视图的Context

除组件外,视图也和Context关联,创建时,构造方法Context入参,在Activity组件中,通过代码new一个View对象,传入的Context即this,代表Activity。

public View(Context context) {
    mContext = context;
    ...
}

View类的getContext()方法,返回内部Context,在视图中需要使用Context的一些方法,是Activity的实现方法或ContextImpl的实现方法。

五、总结

1,Activity、Service和Application的基类都是Context类,内部ContextImpl类是真正实现类。

2,ContextImpl对象的构建方法,Activity类和另外二者不同。

3,开发常用方法,getApplicationContext()方法和getApplication()方法区别,前者是Context抽象方法,在ContextImpl具体中类实现,后者是Activity和Service的方法,相同点是都返回全局Application对象。


任重而道远

你可能感兴趣的:(Context 和组件关系)