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

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

所属板块:第一板块 --- Android 系统基石与运行原理

前置知识:第四篇中的进程孵化(Zygote)、Linux 进程隔离、Binder IPC 机制、ART 虚拟机内存模型

本篇定位 :这是第一板块中最复杂、最深邃的一章。我们将对 Android 系统中的全局信息接口 Context 进行外科手术式的剖析。内容将覆盖 Context 的继承拓扑学ContextImpl 的内部构造ResourcesAssetManager 的 Native 层实现resources.arsc 的二进制解析多 APK 资源加载机制系统配置(Configuration)的动态更新 、以及 LoadedApkClassLoader 的绑定关系。全程无代码封装技巧、无内存泄漏"避免"建议(仅从系统机制解释为何会泄漏),仅保留 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 负责管理多个 ResourcesKeyAssetManager 实例。

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 的内部构造(源码级解析)

ContextImplContext 的唯一实现类。它的构造函数极其复杂,包含大量系统级参数。

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. 计算 ID0x7F010001
  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 规范

相关推荐
ice8130331811 小时前
【Python】调用opencv识别图片人脸位置
人工智能·python·opencv
KaMeidebaby1 小时前
卡梅德生物技术快报|蛋白定制:ACE 抑制肽原辅料工艺全参数|适配蛋白定制的提取 & 酶解标准化实操手册
大数据·人工智能·架构·spark·新浪微博
团象科技1 小时前
中小出海团队运维观察:WordPress站点境外云环境搭建实操路径梳理
大数据·运维·人工智能
沐籽李1 小时前
Proteina-Complexa:NVIDIA 如何把蛋白 Binder 设计推进到全原子生成时代?
大数据·人工智能·算法·英伟达·蛋白质生成
逻辑君1 小时前
神经生物学研究【20260003】
人工智能
大模型最新论文速读1 小时前
StreamMA:把流式输出应用到多智能体系统
论文阅读·人工智能·深度学习·机器学习·自然语言处理
故渊at1 小时前
第一板块:Android 系统基石与运行原理 | 第四篇:进程孵化(Zygote)与 Low Memory Killer 机制
android·虚拟机·zygote·系统启动·low memory·进程孵化
前端不太难1 小时前
大模型之后,谁在决定AI的真实速度?
人工智能·状态模式
落羽的落羽1 小时前
【项目】JsonRpc框架——开发实现2(业务层)
linux·数据结构·c++·人工智能·算法·json·动态规划