Context都没弄明白?

887 阅读3分钟

Context 到底是什么?

一个Context意味着一个场景,一个场景就是我们和软件进行交互的一个过程。

从安卓程序的角度来看,其实一个Activity就是一个Context,一个Service也是一个Context。

一个app其实可以理解成一个大环境,在这个环境里,可以切换到不同的场景,比如你早上先去办公室上班,中午到饭馆吃饭,就是在不同的场景了。

各个Context 类的关系图

先贴个图

Context 作用是啥

有什么用?要看它能做啥,看看主要提供了哪些接口了。

四大组件相关
获取系统/应用资源
获取应用相关信息
文件相关
数据库相关
其它

还挺多的,看起来管得挺多,四大组件都管着,像个 Application 大管家。

管的谁? 哪些事?
四大组件 包括启动 Activity、Broadcast、Service,获取 ContentResolver 等
获取系统/应用资源 包括 AssetManager、PackageManager、Resources、System Service 以及 color、string、drawable 等
数据库(SQLite)相关 包括打开数据库、删除数据库、获取数据库路径等
其它辅助功能 比如设置 ComponentCallbacks,即监听配置信息改变、内存不足等事件的发生

ContextImpl 和 ContextWrapper 有啥区别?

看下ContextWrapper的源码吧

/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
    Context mBase; // 注意这个mBase

    public ContextWrapper(Context base) {
        mBase = base;
    }

    /**
    * Set the base context for this ContextWrapper. All calls will then be
    * delegated to the base context. Throws
    * IllegalStateException if a base context has already been set.
    *
    * @param base The new base context for this wrapper.
    */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    /**
    * @return the base context as set by the constructor or setBaseContext
    */
    public Context getBaseContext() {
        return mBase; // 这就是Base Context 了
    }

    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

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

    @Override
    public PackageManager getPackageManager() {
        return mBase.getPackageManager();
    }
    ...

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

ContextImpl呢?

/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {

    private int mThemeResource = 0;
    private Resources.Theme mTheme = null;
    private @NonNull Resources mResources;
    
    // 用于创建 Activity Context
    static ContextImpl createActivityContext(...) {
        ContextImpl context = new ContextImpl(...);
        context.setResources(resourcesManager.createBaseActivityResources(...));
        return context;
    }
    
    // 用于创建 Application Context、Service Context
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        ContextImpl context = new ContextImpl(...);
        context.setResources(packageInfo.getResources());
        return context;
    }
    
    private static Resources createResources(...) {
        return ResourcesManager.getInstance().getResources(...);
    }

    // ContextThemeWrapper 没有重写父类的 setResources
    // 因此会调用 mBase 的 setResources,即和 ContextImpl 的行为一样
    void setResources(Resources r) {
        if (r instanceof CompatResources) {
            ((CompatResources) r).setContext(this);
        }
        mResources = r;
    }
    
    @Override
    public Resources getResources() {
        return mResources;
    }
    ...
Class Diff
ContextImpl 真正实现了Context中所有的函数 (真正厉害的!)
ContextWrapper Context 的代理类,所有的操作都是通过内部成员 mBase 完成的
ContextThemeWrapper 内部包含了与主题相关的接口,有自己的 Theme 以及 Resource,并且 Resource 可以传入自己的配置初始化

P.S.

主题是啥?

就是指在AndroidManifest.xml中通过 android:themeApplication 或者 Activity 指定的主题。

只有Activity才需要主题,Service是默默的后台工作者,不需要穿的那么鲜艳,所以Service直接继承 ContextWrapper 就好了。

Activity、Service、Application 各自的Context有啥区别?

不同组件创建ContextImpl的方式:

API
Activity 调用 createBaseContextForActivity
Service/Application 调用 createAppContext
Provider 调用 createPackageContext
BroadcastReceiver 直接从 Application.getBaseContext() 来获取 ContextImpl 对象

参考: