Android 面试:一个进程有多少个 -Context- 对象?看似初级的问题,答的好的人确不多
目录
作者:彭旭锐链接:https://www.jianshu.com/p/51d63a1ffb95
1. Context 继承关系
Context
是一个抽象类,具体的实现类有Application
、Activity
、Service
与ContextImpl
。为方便区分,通常也称为ApplicationConext
、ActivityContext
与ServiceContext
,具体 UML 类图如下:
可以看到,除了我们熟悉的Application
、Activity
、Service
,继承关系上还有ContextWrapper
与ContextThemeWrapper
,它们的作用 & 职责如下:
ContextWrapper
定义:
Context
包装类作用:持有基础对象的引用
(mBase)
,并且实现了Context
接口,将所有方法调用请求转发给基础对象
// ContextWrapper.java
Context mBase;
public ContextWrapper(Context base) {mBase = base;}
// 【分析点 1:绑定基础对象(见 todo)】protected void attachBaseContext(Context base) {if (mBase != null) {throw new IllegalStateException("Base context
already set");}mBase = base;}
@Overridepublic void startActivity(Intent intent) {// 转发给 mBasemBase.startActivity(intent);}
ContextThemeWrapper
定义:
Context
包装类【todo】
2. Application 对象
我们都知道,在启动四大组件(Activity、Service、ContentProvider, BroadcastReceiver)
时,如果对应的进程未启动,就需要先创建进程,相应地也会创建一个Application
对象。简单来说:
在
system_server
进程,通过AMS#getProcessRecordLocked(...)
获取进程信息(ProcessRecord)
;若不存在,则调用
AMS#startProcessLocked(...)
创建进程在
Zygote
孵化目标进程之后,在目标进程反射执行ActivityThread#main()
,并最终在ActivityThread#handleBindApplication(...)
中创建Application
对象
// ActivityThread.java
Application mInitialApplication;final ArrayList<Application> mAllApplications = new ArrayList<Application>();
private void handleBindApplication(AppBindData data) {// ...Application app;// data.info 为 LoadedApk.javaapp = data.info.makeApplication(data.restrictedBackupMode, null);// ...mInitialApplication = app;// ...}
// LoadedApk.java
private Application mApplication;
public Application makeApplication(...) {// 创建基础对象 ContextImplContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);// 反射调用创建 Application 对象 app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);// ContextImpl 也持有包装类 ApplicationappContext.setOuterContext(app);// 保存创建的 Application 对象 mActivityThread.mAllApplications.add(app);mApplication = app;}
// Instrumentation.java
public Application newApplication(ClassLoader cl, String className, Context context) {// 反射调用创建 Application 对象 Application app = getFactory(context.getPackageName()).instantiateApplication(cl, className);app.attach(context);return app;}
// Application.javafinal void attach(Context context) {// 设置包装类 Application 的基础对象 attachBaseContext(context);mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;}
总结要点如下:
一个
Application
对象相当于存在两个Context
对象(代理对象与基础对象)Application
对象与ContextImpl
对象相互引用
3. Activity 对象
这一节我们来看Activity
对象的创建过程,简单来说:
创建
Application
对象之后,最后在ActivityThread#handleLaunchActivity(...)
中创建Activity
对象
// ActivityThread.java
public Activity handleLaunchActivity(...) {// ...final Activity a = performLaunchActivity(r, customIntent);// ...}
private Activity performLaunchActivity(...) {// ...// 创建基础对象 ContextImplContextImpl appContext = ContextImpl.createActivityContext(...);// 反射调用创建 Activity 对象 Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
评论