第一板块:Android 系统基石与运行原理 | 第五篇:Context 上下文与资源配置体系

第一板块: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 关系说明:

  1. 实线空心三角形箭头(<|--) :表示继承(Generalization) 。例如 Activity 继承自 ContextThemeWrapper。
  2. 虚线空心三角形箭头(..|>) :表示实现(Realization) 。例如 ContextImpl 实现了 Context 接口。
  3. 实线菱形箭头(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)。

  1. 构造 :ContextImpl 创建时,调用 AssetManager.createAssetManager()(JNI 方法)。
  2. 加载路径 :AssetManager 会加载以下路径的资源:
    • /system/framework/framework-res.apk(系统资源)
    • /data/app/[package_name]/base.apk(应用资源)
    • /data/app/[package_name]/split_config.arm64_v8a.apk(Split APK)
  3. 资源表解析 :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) 时:

  1. 计算 ID :0x7F010001。
  2. 定位 Package :找到 0x7F 对应的 Package(com.example.app)。
  3. 定位 Type :找到 01 对应的 Type(string)。
  4. 定位 Entry :找到 0001 对应的 Entry。
  5. 应用配置 :根据当前 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 包。它负责:

  1. 管理 ClassLoader(用于加载 APK 中的 .dex 类)。
  2. 管理 Resources(确保同一个 APK 的资源只加载一次)。
  3. 管理 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 容易导致内存泄漏?

  1. 引用链 :Activity -> ContextImpl -> Resources -> Configuration -> Display -> WindowManagerService (Binder 引用)。
  2. 长生命周期对象 :如果单例(Singleton)持有 Activity Context,那么单例的生命周期(应用进程)长于 Activity 的生命周期。
  3. 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 规范

相关推荐
IT_陈寒3 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
yumgpkpm3 小时前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
程序员cxuan3 小时前
腾讯又来一王炸,开源版 WorkBuddy 太夯了!
人工智能·后端·程序员
邓工说电3 小时前
智慧断路器安全吗?数据加密、离线保护与合规认证全解读
大数据·数据库·人工智能·智能断路器·炜晔科技
阿里云大数据AI技术3 小时前
Lance 数据检索怎么选,当然阿里云 Milvus 向量湖
人工智能
出海客3 小时前
跨境电商多语言客服知识库怎么建:资料结构、检索边界与人工升级
大数据·人工智能
xsd202411184 小时前
从自主导航到视觉读表:一台工业巡检机器人的全栈技术链路拆解
人工智能
袁哥大话安全4 小时前
巡隐WEBSHELL扫描软件
人工智能·安全·web
论文复现现场4 小时前
8卡4090能跑70B吗?Llama-2显存预算、QLoRA与通信瓶颈
人工智能·深度学习·分布式训练·llama·显存·qlora·算家云
酷虎软件4 小时前
如何用AI创作AI歌曲AI音乐
人工智能