Android Context简介

Context在整个系统里的核心表现形式如下图:
image.png
简单来讲,Context是一个抽象类,定义了一系列的抽象方法,它的具体实现由ContextImpl来完成。ContextWrapper虽然也继承了Context,但是它的方法的具体实现是由mBase(即ContextImpl实例)来完成的,故ContextWrapper也是一个代理类。Application、Service和ContextThemeWrapper都是继承于ContextWrapper。ContextThemeWrapper与ContextWrapper的主要区别在于重写了Resource和Theme,Activity是ContextThemeWrapper的具体使用。

看懂了上图这个继承关系,就不难理解一个进程里面Context的实例个数的计算方式了:
Context数 = Activity数 + Service数 + 1(Application数必定为1)

Context
/**
* Interface to global information about an application environment.  This is
* an abstract class whose implementation is provided by
* the Android system.  It
* allows access to application-specific resources and classes, as well as
* up-calls for application-level operations such as launching activities,
* broadcasting and receiving intents, etc.
*/
public abstract class Context {
    
    // 四大组件相关
    public abstract void startActivity(@RequiresPermission Intent intent);
    public abstract void sendBroadcast(@RequiresPermission Intent intent);
    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                            IntentFilter filter);
    public abstract void unregisterReceiver(BroadcastReceiver receiver);
    public abstract ComponentName startService(Intent service);
    public abstract boolean stopService(Intent service);
    public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);
    public abstract void unbindService(@NonNull ServiceConnection conn);
    public abstract ContentResolver getContentResolver();
    
    // 获取系统/应用资源
    public abstract AssetManager getAssets();
    public abstract Resources getResources();
    public abstract PackageManager getPackageManager();
    public abstract Context getApplicationContext();
    public abstract ClassLoader getClassLoader();
    public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) { ... }
    
    public final String getString(@StringRes int resId) { ... }
    public final int getColor(@ColorRes int id) { ... }
    public final Drawable getDrawable(@DrawableRes int id) { ... }
    public abstract Resources.Theme getTheme();
    public abstract void setTheme(@StyleRes int resid);
    public final TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) { ... }
    
    // 获取应用相关信息
    public abstract ApplicationInfo getApplicationInfo();
    public abstract String getPackageName();
    public abstract Looper getMainLooper();
    public abstract int checkPermission(@NonNull String permission, int pid, int uid);
    
    // 文件相关
    public abstract File getSharedPreferencesPath(String name);
    public abstract File getDataDir();
    public abstract boolean deleteFile(String name);
    public abstract File getExternalFilesDir(@Nullable String type);
    public abstract File getCacheDir();
    ...
    public abstract SharedPreferences getSharedPreferences(String name, @PreferencesMode int mode);
    public abstract boolean deleteSharedPreferences(String name);
    
    // 数据库相关
    public abstract SQLiteDatabase openOrCreateDatabase(...);
    public abstract boolean deleteDatabase(String name);
    public abstract File getDatabasePath(String name);
    ...
    
    // 其它
    public void registerComponentCallbacks(ComponentCallbacks callback) { ... }
    public void unregisterComponentCallbacks(ComponentCallbacks callback) { ... }
    ...
}

public interface ComponentCallbacks {
    void onConfigurationChanged(Configuration newConfig);
    void onLowMemory();
}

从注解可以看出,Context为我们提供了各种交互场景,大体如下:
1、四大组件相关:启动Activity、Service,发送Broadcast,获取ContentRecover等;
2、获取系统/应用资源:获取Asset、Resource、PackageManager、SystemServer、Color、String、Drawable、Theme等;
3、获取应用相关信息:ApplicationInfo、PackageName、MainLooper,检测权限等;
4、文件相关:获取缓存文件、删除文件、操作SharePreference等;
5、数据库相关操作;
6、其他:如注册ComponentCallbacks,监听ConfigurationChanged和LowMemory等。

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; 

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    
    // 这就是经常让人产生疑惑的  Base Context 了
    public Context getBaseContext() {
        return mBase;
    }

    // 下面这些方法全都直接通过 mBase 完成
    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

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

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

类注解来看,ContextWrapper就是Context的代理类,所有抽象方法都是由mBase(即ContextImpl)来完成。

ContextThemeWrapper
/**
* A context wrapper that allows you to modify or replace the theme of the
* wrapped context.
*/
public class ContextThemeWrapper extends ContextWrapper {
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    private Resources mResources;

    public ContextThemeWrapper() {
        super(null);
    }

    public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
        super(base);
        mThemeResource = themeResId;
    }

    public ContextThemeWrapper(Context base, Resources.Theme theme) {
        super(base);
        mTheme = theme;
    }

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }

    // 在 Recource 初始化之前,传入配置信息
    public void applyOverrideConfiguration(Configuration overrideConfiguration) {
        if (mResources != null) {
            throw new IllegalStateException(...);
        }
        if (mOverrideConfiguration != null) {
            throw new IllegalStateException(...);
        }
        mOverrideConfiguration = new Configuration(overrideConfiguration);
    }

    public Configuration getOverrideConfiguration() {
        return mOverrideConfiguration;
    }

    @Override
    public Resources getResources() {
        return getResourcesInternal();
    }

    private Resources getResourcesInternal() {
        if (mResources == null) {
            if (mOverrideConfiguration == null) {
                mResources = super.getResources();
            } else {
                // 根据配置信息初始化 Resource
                // 注意,这里创建了另一个和 Base Context 不同的 Resource
                final Context resContext = createConfigurationContext(mOverrideConfiguration);
                mResources = resContext.getResources();
            }
        }
        return mResources;
    }

    @Override
    public void setTheme(int resid) {
        if (mThemeResource != resid) {
            mThemeResource = resid;
            initializeTheme();
        }
    }
    
    private void initializeTheme() {
        final boolean first = mTheme == null;
        if (first) {
            // 根据 Resource 获取 Theme
            mTheme = getResources().newTheme();
            // 复制内容
            final Resources.Theme theme = getBaseContext().getTheme();
            if (theme != null) {
                mTheme.setTo(theme);
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }

    protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
        theme.applyStyle(resId, true);
    }

    @Override
    public Resources.Theme getTheme() {
        // 只会初始化一次
        if (mTheme != null) {
            return mTheme;
        }

        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                getApplicationInfo().targetSdkVersion);
        initializeTheme();

        return mTheme;
    }

    ...

}

相比于ContextWrapper,ContextThemeWrapper有自己的Theme和Resource,ContextThemeWrapper可以通过传入Configuration来定义自己的Resource和Theme,和mBase(即ContextImpl)无关。

ContextImpl

下面来看一下ContextImpl和ContextThemeWrapper在Theme和Reource代码上的区别

/**
* 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(...);
    }

    //该方法是ContextImpl特有的,Context没有该方法
    void setResources(Resources r) {
        if (r instanceof CompatResources) {
            ((CompatResources) r).setContext(this);
        }
        mResources = r;
    }
    
    @Override
    public Resources getResources() {
        return mResources;
    }
    
    
    /* ---------- 主题相关 ------------ */
    
    @Override
    public void setTheme(int resId) {
        synchronized (mSync) {
            if (mThemeResource != resId) {
                mThemeResource = resId;
                initializeTheme();
            }
        }
    }
    
    // 直接创建一个 Theme 对象,相比 ContextThemeWrapper,缺少了复制theme的代码
    private void initializeTheme() {
        if (mTheme == null) {
            mTheme = mResources.newTheme();
        }
        mTheme.applyStyle(mThemeResource, true);
    }

    @Override
    public Resources.Theme getTheme() {
        synchronized (mSync) {
            // 和 ContextThemeWrapper 基本一样
            if (mTheme != null) {
                return mTheme;
            }

            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                    getOuterContext().getApplicationInfo().targetSdkVersion);
            initializeTheme();

            return mTheme;
        }
    }

}

除了Resource和Theme之外,ContextThemeWrapper还有自己独立的Configuration。

前面一直强调mBase即为ContextImpl,接下来看一下是在什么时候赋值的。

Application

Application继承于ContextWrapper,Application的创建是在LoadedApk中的makeApplication方法中执行的。

public final class LoadedApk {
    ......
    public Application makeApplication(boolean forceDefaultAppClass,
                                       Instrumentation instrumentation) {
        ......
        Application app = null;
        ......
        try {
            ......
            //初始化ContextImpl
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //通过Instrumentation的newApplication方法创建Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ......
        }
        ......
        return app;
    }        
    ......
}

public class Instrumentation {
    ......
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        //将上面生成的ContextImpl赋值给Application
        app.attach(context);
        return app;
    }        
    ......
}

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    ......
    final void attach(Context context) {
        //将上面生成的ContextImpl赋值给mBase
        attachBaseContext(context);
        ......
    }        
    ......
}
Activity

Activity继承于ContextThemeWrapper,启动Activity最终会走到performLaunchActivity。

public final class ActivityThread extends ClientTransactionHandler {
    ......
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        //创建ContextImpl
        ContextImpl appContext = createBaseContextForActivity(r);
        //创建Activity
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ......
        } catch (Exception e) {
            ......
        }

        try {
            ......
            if (activity != null) {
                ......
                //将appContext赋值给activity
                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,
                        r.assistToken);
            ......
            }
            ......

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            ......
        }

        return activity;
    }
    ......

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

public class Activity extends ContextThemeWrapper {
    ......
    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, IBinder assistToken) {
        //将上面的ContextImpl赋值给mBase
        attachBaseContext(context);
        ......
    }
    ......
}
Service

Service继承于ContextWrapper

public final class ActivityThread extends ClientTransactionHandler {
    ......
    private void handleCreateService(CreateServiceData data) {
        ......
        //初始化service
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } catch (Exception e) {
            ......
        }

        try {
            ......
            //创建ContextImpl
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //将context赋值给service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            ......
        } catch (Exception e) {
            ......
        }
    }
    ......
}

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    ......
    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        //给mBase赋值,即上面创建的ContextImpl
        attachBaseContext(context);
        ......
    }        
    ......
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值