文章摘要Activity、Service等本质上是Context,Android开发者应对我们经常打交道的Context对象有一个基本的认识。主要阐述了如下认识:1、如何认识Con
文章摘要
Activity、Service等本质上是Context,Android开发者应对我们经常打交道的Context对象有一个基本的认识。主要阐述了如下认识:
1、如何认识Context。
2、Context的实例化对象ContextImpl对象是如何和Application、Activity、Service发生联系的。
3、Context对象的getResources方法,在一个应用程序中,无论是Application或者不同的Activity界面,返回的是同一个对象。
1、Context认知。
Context译为场景,一个应用程序可以认为是一个工作环境,在这个工作环境中可以存在许多场景,coding代码的场景 ,打电话的场景,开会的场景。这些场景可以类比不同的Activity,service。Activity可以理解为可视化的场景,Service理解为后台工作的场景。
2、从两个角度认识Context。
第一:Activity继承自Context,同时Activity还实现了其他的interface,我们可以这样看,activity在语法上extends了Context,其本质上是一个Context,但同时其实现了许多interface,扩充了Context的功能,扩充之后的类成为Activity或者Service。
第二:Context本质上包含了场景的所有元素,故而设定其为abstract,Activity和Service继承自Context,它们本质上可以认为就是Context。
3、Context继承关系图。
Context是抽象类,ContextWrapper以及ContextThemeWrapper是其包装类,不同的是ContextThemeWrapper需要传入主题。
public ContextThemeWrapper(Context base, int themeres) {
super(base);
mThemeResource = themeres;
}
ContextImpl是真正用来干活的实现类。会通过一些方法将该实现传入到Context中。
ps:关于Wrapper的作用:
- 为其他对象提供一种代理以控制对这个对象的访问。
- 子类中重写实现而不改变原来的Context对象实现。
/**
* 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继承关系图
4、ContextImpl的初始化以及如何与Actvity以及Service等产生联系的。
如下是ContextImpl的初始化调用的地方,有兴趣的可以详细看下。
Context初始化
以Activity为例:
首先,activity的创建,在创建过程中调用attach方法,将Context传入到Activity中。
frameworks/base/core/java/android/app/ActivityThread.java
performLaunchActivity方法,创建Activity对象。
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
接着:调用createBaseContextForActivity得到Context实例化对象:
private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
ContextImpl appCOntext= ContextImpl.createActivityContext(this, r.packageInfo, r.token);
appContext.setOuterContext(activity);
Context baseCOntext= appContext;
}
最后,调用Activity的attach方法,将Context对象,传入Activity中。
if (activity != null) {
Context appCOntext= createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration cOnfig= new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
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);
}
5、一个应用程序中包括多少Context对象。
Context对象个数 = Activty对象个数+Service对象对象个数+1(Application).。
Context实现
6、Context对象的getResources对象,在一个应用程序中,无论是Application或者不同的Activity界面,返回的是同一个对象。
@Override
public Resources getResources() {
return mResources;
}
mResources对象是在ContextImpl实例化对象中,传递过来的,故而:
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration)
Resources resources = packageInfo.getResources(mainThread);
mResources = resources;
}
从第4步,可以知道,packageInfo来自:r.packageInfo。而r.packageInfo的赋值逻辑如下:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
}
getPackageInfo方法中,会将创建的packageInfo按照以包名为Key的方式保存在ActivityThread.java集合中。
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
synchronized (mResourcesManager) {
WeakReference ref;
if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
: "Loading resource-only package ") + aInfo.packageName
+ " (in " + (mBoundApplication != null
? mBoundApplication.processName : null)
+ ")");
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference(packageInfo));
}
}
return packageInfo;
}
}
总结:
其他Application(getPackageInfoNoCheck)或者
Service(getPackageInfoNoCheck)对象或者
Receiver(getPackageInfoNoCheck),在获取packageInfo的逻辑上,方法不同但都会操作的集合都是mResourcePackages对象。
即:在一个应用程序中r.packageInfo(LoadedApk packageInfo)对象是同一个。