其他
Android上下文Context,学有所得
本文作者
作者:新小梦
链接:
https://juejin.cn/post/7218080719201321021
本文由作者授权发布。
本文分析的内容,可能和之前流程分析有些重复,但每篇文章的主题侧重点不用,分析的内容也不尽相同。
Application与Context的创建和关联
//ActivityThrad#main
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
1、ActivityThread.attach
private void attach(boolean system, long startSeq) {
...
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
...
}
ContextImpl.createAppContext
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
return createAppContext(mainThread, packageInfo, null);
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName) {
...
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,0, null, opPackageName);
context.setResources(packageInfo.getResources());
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
return context;
}
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
@NonNull LoadedApk packageInfo, @Nullable String attributionTag,
@Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user,
int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
//未与Application,或者是Activity、Service绑定,将mOuterContext先指向自己,
mOuterContext = this;
...
//接下来,将应用程序运行的相关信息,引用赋值给ContextImpl的属性
//这样子,通过Context这个入口,就可以访问到相关资源
mMainThread = mainThread;
mToken = activityToken;
mFlags = flags;
if (user == null) {
user = Process.myUserHandle();
}
mUser = user;
//LoadedApk赋值
mPackageInfo = packageInfo;
mSplitName = splitName;
mClassLoader = classLoader;
mResourcesManager = ResourcesManager.getInstance();
String opPackageName;
if (container != null) {
mBasePackageName = container.mBasePackageName;
opPackageName = container.mOpPackageName;
setResources(container.mResources);
mDisplay = container.mDisplay;
mIsAssociatedWithDisplay = container.mIsAssociatedWithDisplay;
mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
opPackageName = ActivityThread.currentPackageName();
} else {
opPackageName = mBasePackageName;
}
}
mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
mAttributionTag = attributionTag;
//前面研究ContentProvider启动流程,mContentResolver初始化的地方
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
2、LoadedApk.makeApplication
//LoadedApk#makeApplication xxm
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
//没有自定义Application,就使用默认的
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
...
final java.lang.ClassLoader cl = getClassLoader();
...
//这里才是真正创建Application上下文的地方,所以上面创建Context实例的作用是?
//分析一
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
...
//分析二
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//分析三
appContext.setOuterContext(app);
...
mActivityThread.mAllApplications.add(app);
//通过AMS创建返回的赋值给mApplication
mApplication = app;
if (instrumentation != null) {
...
instrumentation.callApplicationOnCreate(app);
...
}
return app;
}
3、Instrumentation.newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
getFactory函数返回的是AppComponentFactory类型的实例,其instantiateApplication函数,通过反射创建Application实例。
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
@NonNull String className)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (Application) cl.loadClass(className).newInstance();
}
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
4、ContextImpl.setOuterContext
final void setOuterContext(Context context) {
mOuterContext = context;
}
ApplicationContext的使用
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
Application getApplication() {
return mApplication;
}
在研究Activity的启动流程过程,最终会走到ActivityThread的performLaunchActivity函数。
https://juejin.cn/post/7211800391012565048
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//分析一:创建ContextImpl实例
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
...
java.lang.ClassLoader cl = appContext.getClassLoader();
//分析二:创建Activity实例
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//分析三:appContext关联Activity
appContext.setOuterContext(activity);
//分析四:activity关联appContext
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);
...
return activity;
}
ActivityThread.createBaseContextForActivity
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}
ContextImpl.createActivityContext
static ContextImpl createActivityContext(ActivityThread mainThread,LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) {
...
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
activityInfo.splitName, activityToken, null, 0, classLoader, null);
context.mIsUiContext = true;
context.mIsAssociatedWithDisplay = true;
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final ResourcesManager resourcesManager = ResourcesManager.getInstance();
context.setResources(resourcesManager.createBaseTokenResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
classLoader,
packageInfo.getApplication() == null ? null
: packageInfo.getApplication().getResources().getLoaders()));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
context.getResources());
return context;
}
Activity.attach
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) {
...
attachBaseContext(context);
...
}
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
//ContextThemeWrapper xxm
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
...
}
//ContextWrapper xxm
protected void attachBaseContext(Context base) {
...
mBase = base;
}
到这里Activity和Context就相关关联了。后续在Activity关于Context的相关操作都会传递到实际类型是ContextImpl的mBase中去 。
Service的上下文,其实在Service的启动流程已经分析过了,为了Context的完整性,摘抄过来。
https://juejin.cn/post/7208005892302176317
private void handleCreateService(CreateServiceData data) {
...
Service service = null;
//分析一
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
...
//分析二
context.setOuterContext(service);
//分析三
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
...
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
return createAppContext(mainThread, packageInfo, null);
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
0, null, opPackageName);
context.setResources(packageInfo.getResources());
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
return context;
}
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
...
}
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!