第一板块:Android 系统基石与运行原理 | 第五篇:Context 上下文与资源配置体系
所属板块:第一板块 --- Android 系统基石与运行原理
前置知识:第四篇中的进程孵化(Zygote)、Linux 进程隔离、Binder IPC 机制、ART 虚拟机内存模型
本篇定位 :这是第一板块中最复杂、最深邃的一章。我们将对 Android 系统中的全局信息接口
Context进行外科手术式的剖析。内容将覆盖Context的继承拓扑学 、ContextImpl的内部构造 、Resources与AssetManager的 Native 层实现 、resources.arsc的二进制解析 、多 APK 资源加载机制 、系统配置(Configuration)的动态更新 、以及LoadedApk与ClassLoader的绑定关系。全程无代码封装技巧、无内存泄漏"避免"建议(仅从系统机制解释为何会泄漏),仅保留 Android Framework 的底层定义与系统级规范。
1. 核心结论先行(Thesis Statement)
Context 是 Android 系统中连接应用进程与系统服务的胶水层 。它不仅仅是一个"上下文",而是一个全能的环境句柄(Environment Handle)。
- Context 的本质 :一个抽象接口 ,其具体实现是
ContextImpl。它封装了对系统服务(System Services)的访问、对应用资源(Resources)的访问、以及对文件路径(Files/Database)的访问。 - Context 的数量 :一个 Android 应用中,Context 实例的数量 = Activity 数量 + Service 数量 + 1(Application)。
- 资源加载的本质 :
Context.getResources()返回的Resources对象,内部持有一个AssetManager实例。AssetManager通过 Native 层代码,解析 APK 中的resources.arsc二进制表,建立 Resource ID 到 具体资源路径/值 的映射。 - 多 APK 共存 :Android 支持一个进程加载多个 APK 的资源(如 Split APK、插件化)。
ResourcesManager负责管理多个ResourcesKey和AssetManager实例。
2. Context 继承拓扑学与类型学
2.1 继承树(Inheritance Hierarchy)
Context 的设计采用了**装饰器模式(Decorator Pattern)与桥接模式(Bridge Pattern)**的混合体。以下是严格按照 UML 规范绘制的继承关系图。
#mermaid-svg-WygGcUa8g4XCCNpZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WygGcUa8g4XCCNpZ .error-icon{fill:#552222;}#mermaid-svg-WygGcUa8g4XCCNpZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WygGcUa8g4XCCNpZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WygGcUa8g4XCCNpZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WygGcUa8g4XCCNpZ .marker.cross{stroke:#333333;}#mermaid-svg-WygGcUa8g4XCCNpZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WygGcUa8g4XCCNpZ p{margin:0;}#mermaid-svg-WygGcUa8g4XCCNpZ g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-WygGcUa8g4XCCNpZ g.classGroup text .title{font-weight:bolder;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster-label text{fill:#333;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster-label span{color:#333;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster-label span p{background-color:transparent;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster text{fill:#333;}#mermaid-svg-WygGcUa8g4XCCNpZ .cluster span{color:#333;}#mermaid-svg-WygGcUa8g4XCCNpZ .nodeLabel,#mermaid-svg-WygGcUa8g4XCCNpZ .edgeLabel{color:#131300;}#mermaid-svg-WygGcUa8g4XCCNpZ .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-WygGcUa8g4XCCNpZ .label text{fill:#131300;}#mermaid-svg-WygGcUa8g4XCCNpZ .labelBkg{background:#ECECFF;}#mermaid-svg-WygGcUa8g4XCCNpZ .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-WygGcUa8g4XCCNpZ .classTitle{font-weight:bolder;}#mermaid-svg-WygGcUa8g4XCCNpZ .node rect,#mermaid-svg-WygGcUa8g4XCCNpZ .node circle,#mermaid-svg-WygGcUa8g4XCCNpZ .node ellipse,#mermaid-svg-WygGcUa8g4XCCNpZ .node polygon,#mermaid-svg-WygGcUa8g4XCCNpZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WygGcUa8g4XCCNpZ .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ g.clickable{cursor:pointer;}#mermaid-svg-WygGcUa8g4XCCNpZ g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-WygGcUa8g4XCCNpZ g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-WygGcUa8g4XCCNpZ .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-WygGcUa8g4XCCNpZ .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-WygGcUa8g4XCCNpZ .dashed-line{stroke-dasharray:3;}#mermaid-svg-WygGcUa8g4XCCNpZ .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-WygGcUa8g4XCCNpZ #compositionStart,#mermaid-svg-WygGcUa8g4XCCNpZ .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #compositionEnd,#mermaid-svg-WygGcUa8g4XCCNpZ .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #dependencyStart,#mermaid-svg-WygGcUa8g4XCCNpZ .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #dependencyStart,#mermaid-svg-WygGcUa8g4XCCNpZ .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #extensionStart,#mermaid-svg-WygGcUa8g4XCCNpZ .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #extensionEnd,#mermaid-svg-WygGcUa8g4XCCNpZ .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #aggregationStart,#mermaid-svg-WygGcUa8g4XCCNpZ .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #aggregationEnd,#mermaid-svg-WygGcUa8g4XCCNpZ .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #lollipopStart,#mermaid-svg-WygGcUa8g4XCCNpZ .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ #lollipopEnd,#mermaid-svg-WygGcUa8g4XCCNpZ .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-WygGcUa8g4XCCNpZ .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-WygGcUa8g4XCCNpZ .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WygGcUa8g4XCCNpZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WygGcUa8g4XCCNpZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WygGcUa8g4XCCNpZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} mBase
<<abstract>>
Context
+getAssets() : AssetManager
+getResources() : Resources
+getPackageManager() : PackageManager
+getSystemService(String name) : Object
+startActivity(Intent intent) : void
+bindService(Intent intent, ...) : boolean
+getApplicationContext() : Context
+getFilesDir() : File
+checkCallingOrSelfPermission(String permission) : int
<<abstract>>
ContextWrapper
-mBase: Context
+attachBaseContext(Context base) : void
+getBaseContext() : Context
<<abstract>>
ContextThemeWrapper
-mTheme: Resources.Theme
+getTheme() : Resources.Theme
+setTheme(int resid) : void
Activity
+mToken: IBinder
+setContentView(int layoutResID) : void
+findViewById(int id) : View
+getWindow() : Window
+getFragmentManager() : FragmentManager
Service
+onStartCommand(Intent intent, int flags, int startId) : int
+onBind(Intent intent) : IBinder
Application
+onCreate() : void
+onTerminate() : void
<<abstract>>
BackupAgent
+onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) : void
ContextImpl
-mMainThread: ActivityThread
-mPackageInfo: LoadedApk
-mResources: Resources
-mResourcesManager: ResourcesManager
-mOuterContext: Context
+createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, IBinder token) : Context
+createAppContext(ActivityThread mainThread, LoadedApk packageInfo) : Context
UML 关系说明:
- 实线空心三角形箭头(
<|--) :表示继承(Generalization) 。例如Activity继承自ContextThemeWrapper。 - 虚线空心三角形箭头(
..|>) :表示实现(Realization) 。例如ContextImpl实现了Context接口。 - 实线菱形箭头(
o-->) :表示组合(Composition) 。ContextWrapper内部持有一个ContextImpl的强引用(mBase),且ContextImpl的生命周期由ContextWrapper管理。
2.2 关键成员变量与职责
| 类 | 关键成员变量 | 职责 |
|---|---|---|
| ContextImpl | mMainThread: ActivityThread |
持有应用主线程的引用,用于调度 UI 操作。 |
mPackageInfo: LoadedApk |
持有当前 APK 的加载信息,包括 ClassLoader 和资源路径。 |
|
mResources: Resources |
持有资源对象,用于访问应用资源。 | |
mOuterContext: Context |
指向外部的包装者(Activity/Service/Application),用于回调。 | |
| ContextWrapper | mBase: Context |
核心 。指向真正的实现者 ContextImpl。所有方法都委托给它。 |
| ContextThemeWrapper | mTheme: Resources.Theme |
持有当前上下文的主题资源。 |
| Activity | mToken: IBinder |
窗口令牌。用于在 WMS 中标识该 Activity 的窗口,是 Dialog 能弹出的前提。 |
mWindow: Window |
持有窗口对象,用于管理 UI 界面。 |
3. Context 的实例化与附着机制(Deep Dive)
3.1 ActivityThread 中的创建流程
ActivityThread 是应用的主线程(UI 线程),也是所有组件的创建工厂。
Activity Application ContextImpl ActivityThread ActivityManagerService Zygote Activity Application ContextImpl ActivityThread ActivityManagerService Zygote #mermaid-svg-ZEOXVsI2EGwnVmWE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZEOXVsI2EGwnVmWE .error-icon{fill:#552222;}#mermaid-svg-ZEOXVsI2EGwnVmWE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZEOXVsI2EGwnVmWE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZEOXVsI2EGwnVmWE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZEOXVsI2EGwnVmWE .marker.cross{stroke:#333333;}#mermaid-svg-ZEOXVsI2EGwnVmWE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZEOXVsI2EGwnVmWE p{margin:0;}#mermaid-svg-ZEOXVsI2EGwnVmWE .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ZEOXVsI2EGwnVmWE text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-ZEOXVsI2EGwnVmWE .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-ZEOXVsI2EGwnVmWE .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-ZEOXVsI2EGwnVmWE #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-ZEOXVsI2EGwnVmWE .sequenceNumber{fill:white;}#mermaid-svg-ZEOXVsI2EGwnVmWE #sequencenumber{fill:#333;}#mermaid-svg-ZEOXVsI2EGwnVmWE #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-ZEOXVsI2EGwnVmWE .messageText{fill:#333;stroke:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ZEOXVsI2EGwnVmWE .labelText,#mermaid-svg-ZEOXVsI2EGwnVmWE .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .loopText,#mermaid-svg-ZEOXVsI2EGwnVmWE .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-ZEOXVsI2EGwnVmWE .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-ZEOXVsI2EGwnVmWE .noteText,#mermaid-svg-ZEOXVsI2EGwnVmWE .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-ZEOXVsI2EGwnVmWE .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ZEOXVsI2EGwnVmWE .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ZEOXVsI2EGwnVmWE .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-ZEOXVsI2EGwnVmWE .actorPopupMenu{position:absolute;}#mermaid-svg-ZEOXVsI2EGwnVmWE .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-ZEOXVsI2EGwnVmWE .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-ZEOXVsI2EGwnVmWE .actor-man circle,#mermaid-svg-ZEOXVsI2EGwnVmWE line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-ZEOXVsI2EGwnVmWE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进程创建阶段 Activity 启动阶段 fork 新进程bindApplication()createAppContext(mActivityThread, mLoadedApk)new Application()attachBaseContext(contextImpl)onCreate()application 创建完成scheduleLaunchActivity()createActivityContext(r.token, r.activityInfo, r.parent)new Activity()attach(contextImpl, r.token, ...)onCreate()
3.2 ContextImpl 的内部构造(源码级解析)
ContextImpl 是 Context 的唯一实现类。它的构造函数极其复杂,包含大量系统级参数。
java
// android.app.ContextImpl (简化版源码)
class ContextImpl extends Context {
// 核心成员变量
final ActivityThread mMainThread; // 主线程
final LoadedApk mPackageInfo; // 加载的 APK 信息(非常重要)
final Resources mResources; // 资源对象
private final ResourcesManager mResourcesManager; // 资源管理器(单例)
private final Display mDisplay; // 显示设备
private final UserHandle mUser; // 用户句柄(多用户支持)
private Context mOuterContext; // 外部包装者(Activity/Service/App)
// 构造器(私有,只能通过静态方法创建)
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
ClassLoader classLoader) {
mMainThread = mainThread;
mPackageInfo = packageInfo;
mResources = packageInfo.getResources();
// ... 省略大量初始化代码
}
}
4. 资源加载体系(The Resource Loading Pipeline)
这是本篇最复杂的部分。我们将深入到 resources.arsc 的二进制结构。
4.1 资源加载全链路
#mermaid-svg-GKEfr2cFPwFKtLfO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GKEfr2cFPwFKtLfO .error-icon{fill:#552222;}#mermaid-svg-GKEfr2cFPwFKtLfO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GKEfr2cFPwFKtLfO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GKEfr2cFPwFKtLfO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GKEfr2cFPwFKtLfO .marker.cross{stroke:#333333;}#mermaid-svg-GKEfr2cFPwFKtLfO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GKEfr2cFPwFKtLfO p{margin:0;}#mermaid-svg-GKEfr2cFPwFKtLfO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster-label text{fill:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster-label span{color:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster-label span p{background-color:transparent;}#mermaid-svg-GKEfr2cFPwFKtLfO .label text,#mermaid-svg-GKEfr2cFPwFKtLfO span{fill:#333;color:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO .node rect,#mermaid-svg-GKEfr2cFPwFKtLfO .node circle,#mermaid-svg-GKEfr2cFPwFKtLfO .node ellipse,#mermaid-svg-GKEfr2cFPwFKtLfO .node polygon,#mermaid-svg-GKEfr2cFPwFKtLfO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GKEfr2cFPwFKtLfO .rough-node .label text,#mermaid-svg-GKEfr2cFPwFKtLfO .node .label text,#mermaid-svg-GKEfr2cFPwFKtLfO .image-shape .label,#mermaid-svg-GKEfr2cFPwFKtLfO .icon-shape .label{text-anchor:middle;}#mermaid-svg-GKEfr2cFPwFKtLfO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GKEfr2cFPwFKtLfO .rough-node .label,#mermaid-svg-GKEfr2cFPwFKtLfO .node .label,#mermaid-svg-GKEfr2cFPwFKtLfO .image-shape .label,#mermaid-svg-GKEfr2cFPwFKtLfO .icon-shape .label{text-align:center;}#mermaid-svg-GKEfr2cFPwFKtLfO .node.clickable{cursor:pointer;}#mermaid-svg-GKEfr2cFPwFKtLfO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GKEfr2cFPwFKtLfO .arrowheadPath{fill:#333333;}#mermaid-svg-GKEfr2cFPwFKtLfO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GKEfr2cFPwFKtLfO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GKEfr2cFPwFKtLfO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GKEfr2cFPwFKtLfO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GKEfr2cFPwFKtLfO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GKEfr2cFPwFKtLfO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster text{fill:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO .cluster span{color:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GKEfr2cFPwFKtLfO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GKEfr2cFPwFKtLfO rect.text{fill:none;stroke-width:0;}#mermaid-svg-GKEfr2cFPwFKtLfO .icon-shape,#mermaid-svg-GKEfr2cFPwFKtLfO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GKEfr2cFPwFKtLfO .icon-shape p,#mermaid-svg-GKEfr2cFPwFKtLfO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GKEfr2cFPwFKtLfO .icon-shape .label rect,#mermaid-svg-GKEfr2cFPwFKtLfO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GKEfr2cFPwFKtLfO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GKEfr2cFPwFKtLfO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GKEfr2cFPwFKtLfO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用进程
创建
持有
解析
映射
ContextImpl.getResources()
ResourcesManager.getInstance()
ResourcesKey (Key = APK Path + Locale + Density)
AssetManager
resources.arsc (APK内)
TypedArray / XmlBlock
4.2 AssetManager 的 Native 层实现
AssetManager 是资源加载的核心引擎 。它的大部分逻辑在 Native 层(libandroid_runtime.so)。
- 构造 :
ContextImpl创建时,调用AssetManager.createAssetManager()(JNI 方法)。 - 加载路径 :
AssetManager会加载以下路径的资源:/system/framework/framework-res.apk(系统资源)/data/app/[package_name]/base.apk(应用资源)/data/app/[package_name]/split_config.arm64_v8a.apk(Split APK)
- 资源表解析 :
AssetManager读取 APK 中的resources.arsc文件,构建一个资源 ID 到资源路径的映射表。
4.3 resources.arsc 的二进制结构
resources.arsc 是一个高度优化的二进制表。理解它需要了解以下结构:
resources.arsc
├── Resource Table Header
├── Package Header (com.example.app)
│ ├── Type String Pool (layout, string, drawable...)
│ ├── Key String Pool (main, activity_main...)
│ └── Resource Entries
│ ├── Entry 1 (0x7F010001) -> "Hello World"
│ ├── Entry 2 (0x7F020001) -> "res/drawable/icon.png"
│ └── Entry 3 (0x7F030001) -> "res/layout/main.xml"
Resource ID 的组成:
- 0x7F:Package ID(应用包)
- 01:Type ID(资源类型,如 string)
- 0001:Entry ID(具体条目)
4.4 资源查找算法(Resolution Algorithm)
当调用 getText(R.string.app_name) 时:
- 计算 ID :
0x7F010001。 - 定位 Package :找到
0x7F对应的 Package(com.example.app)。 - 定位 Type :找到
01对应的 Type(string)。 - 定位 Entry :找到
0001对应的 Entry。 - 应用配置 :根据当前 Configuration(Locale=zh_CN, Density=480dpi),选择最合适的资源。
- 先查
values-zh-rCN/strings.xml - 再查
values-zh/strings.xml - 最后查
values/strings.xml
- 先查
5. 多 APK 资源加载与 Split APK
Android 5.0 引入了 Split APK 机制,允许将一个 APK 拆分成多个。
5.1 Split APK 结构
/data/app/com.example.app/
├── base.apk # 基础 APK
├── split_config.arm64_v8a.apk # ABI 分割
├── split_config.en.apk # 语言分割
└── split_config.xxhdpi.apk # 屏幕密度分割
5.2 ResourcesManager 的管理策略
ResourcesManager 维护一个 ArrayMap<ResourcesKey, WeakReference<Resources>>。每当加载一个新的 Split APK,它会创建一个新的 ResourcesKey,并创建一个新的 AssetManager,将 Split APK 的路径添加到 AssetManager 中。
java
// AssetManager 添加路径(Native 层)
AssetManager.addAssetPath("/data/app/com.example.app/base.apk");
AssetManager.addAssetPath("/data/app/com.example.app/split_config.en.apk");
6. 系统配置变化(Configuration Changes)
6.1 配置变化的系统级处理
当系统配置发生变化(如旋转屏幕、切换语言)时,系统会如何处理?
Resources Activity ActivityThread 系统 (WindowManagerService) Resources Activity ActivityThread 系统 (WindowManagerService) #mermaid-svg-BBV9VJjNuMaHOqA9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BBV9VJjNuMaHOqA9 .error-icon{fill:#552222;}#mermaid-svg-BBV9VJjNuMaHOqA9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BBV9VJjNuMaHOqA9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BBV9VJjNuMaHOqA9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BBV9VJjNuMaHOqA9 .marker.cross{stroke:#333333;}#mermaid-svg-BBV9VJjNuMaHOqA9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BBV9VJjNuMaHOqA9 p{margin:0;}#mermaid-svg-BBV9VJjNuMaHOqA9 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-BBV9VJjNuMaHOqA9 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-BBV9VJjNuMaHOqA9 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-BBV9VJjNuMaHOqA9 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-BBV9VJjNuMaHOqA9 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-BBV9VJjNuMaHOqA9 .sequenceNumber{fill:white;}#mermaid-svg-BBV9VJjNuMaHOqA9 #sequencenumber{fill:#333;}#mermaid-svg-BBV9VJjNuMaHOqA9 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-BBV9VJjNuMaHOqA9 .messageText{fill:#333;stroke:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-BBV9VJjNuMaHOqA9 .labelText,#mermaid-svg-BBV9VJjNuMaHOqA9 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .loopText,#mermaid-svg-BBV9VJjNuMaHOqA9 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-BBV9VJjNuMaHOqA9 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-BBV9VJjNuMaHOqA9 .noteText,#mermaid-svg-BBV9VJjNuMaHOqA9 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-BBV9VJjNuMaHOqA9 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-BBV9VJjNuMaHOqA9 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-BBV9VJjNuMaHOqA9 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-BBV9VJjNuMaHOqA9 .actorPopupMenu{position:absolute;}#mermaid-svg-BBV9VJjNuMaHOqA9 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-BBV9VJjNuMaHOqA9 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-BBV9VJjNuMaHOqA9 .actor-man circle,#mermaid-svg-BBV9VJjNuMaHOqA9 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-BBV9VJjNuMaHOqA9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 配置变化 (e.g., Orientation changed)relaunchActivity()onPause()onSaveInstanceState()onDestroy()new Activity()attach(new ContextImpl)updateConfiguration()重新加载对应密度的资源onCreate()
6.2 配置不变的陷阱
如果在 AndroidManifest.xml 中声明 android:configChanges="orientation|screenSize",Activity 不会销毁重建,而是回调 onConfigurationChanged()。
学术定义 :此时 Resources 对象不会自动更新。如果此时获取资源,可能会得到旧配置下的资源(例如旋转屏幕后,图片密度未变)。正确的做法是手动调用 getResources().updateConfiguration()。
7. Context 与 Binder IPC
Context 是访问系统服务的入口。
7.1 getSystemService 的实现
java
// ContextImpl.java
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
// SystemServiceRegistry.java
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
关键点 :getSystemService 返回的并不是服务的实现,而是一个本地代理(Proxy) 。真正的服务运行在 system_server 进程中,Context 通过 Binder IPC 与它通信。
8. LoadedApk 与 ClassLoader 的绑定
LoadedApk 代表一个已经加载的 APK 包。它负责:
- 管理
ClassLoader(用于加载 APK 中的.dex类)。 - 管理
Resources(确保同一个 APK 的资源只加载一次)。 - 管理
ReceiverDispatcher(广播接收器的分发)。
java
// LoadedApk.java
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
// 创建 PathClassLoader
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(
mBaseCodePath, mDataDir, mNativeLibraryDir, mClassLoader);
}
return mClassLoader;
}
}
9. Context 的内存泄漏机制(System Level)
从系统角度看,为什么 Activity Context 容易导致内存泄漏?
- 引用链 :
Activity->ContextImpl->Resources->Configuration->Display->WindowManagerService(Binder 引用)。 - 长生命周期对象 :如果单例(Singleton)持有
ActivityContext,那么单例的生命周期(应用进程)长于 Activity 的生命周期。 - GC Root :单例是 GC Root。它引用的 Activity 无法被回收,即使 Activity 已经调用了
onDestroy()。
学术结论 :必须使用 Application Context 来初始化全局单例,切断 Activity 与 GC Root 的直接引用链。
10. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| Context 的本质 | 一个封装了应用环境信息的接口,具体实现由 ContextImpl 承担。 |
| Context 的类型 | 分为 Application、Activity、Service 三种,生命周期和作用域各不相同。 |
| 资源加载机制 | ContextImpl -> ResourcesManager -> AssetManager -> resources.arsc。 |
| 配置变化 | 系统配置变化会导致 Activity 销毁重建,并触发 Resources 的重新加载。 |
| 系统服务访问 | Context 是获取系统服务代理(Binder Proxy)的唯一入口。 |
| ClassLoader 绑定 | LoadedApk 将 APK 的类加载器与资源加载器绑定在一起。 |
下一篇预告 :第二板块:Android 四大组件标准化学理 | 第六篇:四大组件架构总论与 Manifest 规范