热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Context总结

文章摘要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总结》 Context继承关系图

4、ContextImpl的初始化以及如何与Actvity以及Service等产生联系的。
如下是ContextImpl的初始化调用的地方,有兴趣的可以详细看下。

《Context总结》 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总结》 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)对象是同一个。


推荐阅读
author-avatar
中国地产人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有