编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

    • 库的解读

    • 专栏博客

      • 系统启动Zygote
      • Binder通信原理
      • Handler消息机制
      • Activity启动原理
      • 四大组件原理分析
        • AMS与组件管理
        • View绑制与渲染
        • 事件分发机制
        • Surface渲染原理
        • 自定义View设计
        • WMS窗口管理
        • PMS与APK安装
        • 虚拟机与类加载
        • 内存管理与GC
        • 线程与并发编程
        • 性能优化与监控
        • 序列化与数据存储
        • 组件化与路由设计
        • 插件化与热修复
        • NDK开发实践
        • WebView核心设计
        • ADB常见使用操作
      • 智能硬件

    • iOS开发和进阶

    • Web开发和进阶

    • Linux应用开发

    • Apps
    • Android提升进阶
    • 专栏博客
    杨充
    2026-04-14
    目录

    四大组件原理分析

    # 05.四大组件原理分析

    # 目录介绍

    • 01.四大组件概述
      • 1.1 四大组件的设计思想
      • 1.2 组件注册与发现机制
      • 1.3 组件间通信的本质
    • 02.Activity原理深入分析
      • 2.1 Activity的创建流程
      • 2.2 生命周期的驱动机制
      • 2.3 onSaveInstanceState与恢复
      • 2.4 Activity的窗口关联
    • 03.Activity启动模式源码分析
      • 3.1 四种启动模式的实现
      • 3.2 Intent Flags对Task的影响
      • 3.3 taskAffinity的作用原理
      • 3.4 多实例与SingleInstance的区别
    • 04.Service原理深入分析
      • 4.1 startService与bindService对比
      • 4.2 Service的生命周期状态机
      • 4.3 IntentService的设计原理
      • 4.4 JobIntentService与WorkManager
    • 05.BroadcastReceiver原理深入分析
      • 5.1 静态注册与动态注册对比
      • 5.2 广播分发的线程模型
      • 5.3 LocalBroadcast的实现原理
      • 5.4 有序广播的中止与修改
    • 06.ContentProvider原理深入分析
      • 6.1 Provider的跨进程通信机制
      • 6.2 Cursor的数据传输原理
      • 6.3 ContentObserver通知机制
      • 6.4 FileProvider的实现原理
    • 07.组件间通信机制
      • 7.1 Intent的数据传递原理
      • 7.2 Bundle的序列化机制
      • 7.3 Binder传输大小限制
      • 7.4 大数据传输方案
    • 08.组件的进程间交互
      • 8.1 跨进程启动组件的流程
      • 8.2 远程Service的Binder通信
      • 8.3 ContentProvider的跨进程查询
      • 8.4 PendingIntent的延迟执行
    • 09.组件安全与权限控制
      • 9.1 组件的exported属性
      • 9.2 Permission保护组件
      • 9.3 签名级权限的应用
      • 9.4 Android 12的安全增强
    • 10.总结与面试要点
      • 10.1 四大组件对比总结
      • 10.2 高频面试题解析
      • 10.3 最佳实践建议

    # 01.四大组件概述

    # 1.1 四大组件的设计思想

    Android的四大组件(Activity、Service、BroadcastReceiver、ContentProvider)是应用开发的基石。它们的设计遵循了一个核心思想:组件化与松耦合。

    四大组件的设计定位:
    ┌──────────────────────────────────────────────────────┐
    │ Activity    → 用户界面交互的载体,一个屏幕就是一个Activity │
    │ Service     → 后台长时间运行的任务,无界面                  │
    │ Broadcast   → 系统级的事件通知与订阅机制                    │
    │ Provider    → 跨进程的结构化数据共享                       │
    └──────────────────────────────────────────────────────┘
    
    设计核心原则:
    1.声明式注册:组件在Manifest中声明,系统统一管理
    2.生命周期托管:组件的创建和销毁由系统控制,不是应用自己
    3.Intent驱动:组件间通过Intent通信,实现松耦合
    4.跨进程透明:调用者不需要关心目标组件在哪个进程
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    这种设计使得Android应用可以被灵活组合——一个应用可以启动另一个应用的Activity、绑定其Service、接收其广播、查询其数据,而不需要了解对方的实现细节。

    # 1.2 组件注册与发现机制

    所有组件都需要在AndroidManifest.xml中声明(动态注册的BroadcastReceiver除外),PMS在系统启动时扫描所有APK并解析Manifest,建立全局的组件注册表。

    组件注册与发现流程:
    开发者在Manifest中声明组件
      → PMS启动时解析所有APK的Manifest
        → 组件信息存入ComponentResolver
          → 运行时通过Intent查找:
             显式Intent → 直接查ComponentName
             隐式Intent → IntentFilter匹配
    
    1
    2
    3
    4
    5
    6
    7

    # 1.3 组件间通信的本质

    四大组件间的通信本质上都是通过Binder IPC完成的。即使是同一个进程内的组件通信,也要经过AMS:

    组件通信的Binder链路:
    应用A进程                 SystemServer                应用B进程
    startActivity() ──→ AMS.startActivity() ──→ scheduleLaunchActivity()
    startService()  ──→ AMS.startService()  ──→ scheduleCreateService()
    sendBroadcast() ──→ AMS.broadcastIntent()──→ scheduleRegisteredReceiver()
    query()         ──→ AMS.getProvider()   ──→ Provider.query()(直接Binder)
    
    1
    2
    3
    4
    5
    6

    # 02.Activity原理深入分析

    # 2.1 Activity的创建流程

    当AMS决定启动一个Activity后,通过Binder通知目标进程创建Activity实例:

    // AMS侧发起
    // Android 9+通过ClientTransaction机制
    ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken);
    clientTransaction.addCallback(LaunchActivityItem.obtain(intent, ...));
    clientTransaction.setLifecycleStateRequest(ResumeActivityItem.obtain(isForward));
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    
    // 应用端处理
    // TransactionExecutor.execute()
    //   → LaunchActivityItem.execute()
    //     → ActivityThread.handleLaunchActivity()
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // 1.通过Instrumentation反射创建Activity实例
        Activity activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        
        // 2.创建Context(ContextImpl)
        ContextImpl appContext = createBaseContextForActivity(r);
        
        // 3.调用Activity.attach()(关联Window、设置WindowManager)
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, title, r.parent, ...);
        
        // 4.调用onCreate
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        
        return activity;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    Activity创建的关键步骤:
    1. Instrumentation.newActivity() → 反射创建Activity实例
    2. Activity.attach() → 创建PhoneWindow、设置WindowManager
    3. onCreate() → 开发者设置ContentView
    4. onStart() → Activity可见
    5. onResume() → Activity可交互
       → WindowManager.addView() → WMS创建窗口
    
    1
    2
    3
    4
    5
    6
    7

    # 2.2 生命周期的驱动机制

    Activity的生命周期完全由AMS(ATMS)驱动。AMS通过Binder通知应用端执行对应的生命周期回调:

    Android 9+的生命周期驱动机制(ClientTransaction):
    
    AMS侧:
      创建ClientTransaction
      → 添加LifecycleStateRequest(目标状态)
      → 通过IApplicationThread发送到应用端
    
    应用端:
      TransactionExecutor.execute()
      → cycleToPath():计算当前状态到目标状态的路径
      → 逐个执行路径上的每个生命周期回调
    
    示例:从RESUMED到STOPPED
      路径:RESUMED → PAUSED → STOPPED
      执行:handlePauseActivity() → handleStopActivity()
    
    示例:从STOPPED到RESUMED
      路径:STOPPED → STARTED → RESUMED
      执行:handleStartActivity() → handleResumeActivity()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    # 2.3 onSaveInstanceState与恢复

    状态保存时机:
    - Activity被系统回收前(而非用户主动关闭)
    - 具体触发点:onStop之前(Android P+在onStop之后)
    - 场景:旋转屏幕、按Home键、内存不足被回收
    
    保存流程:
    AMS通知scheduleStopActivity(saveState=true)
      → handleStopActivity()
        → performSaveInstanceState()
          → onSaveInstanceState(outState)
            → Window.saveHierarchyState() ← View树的状态自动保存
        → 将Bundle通过Binder传给AMS保存在ActivityRecord中
    
    恢复流程:
    AMS启动Activity时将savedInstanceState传给应用端
      → performLaunchActivity()
        → onCreate(savedInstanceState) ← 开发者手动恢复
        → onRestoreInstanceState(savedInstanceState) ← 系统自动恢复View树
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 2.4 Activity的窗口关联

    每个Activity关联一个Window(PhoneWindow),Window负责管理DecorView和视图层次:

    Activity与Window的关系:
    Activity
    ├── mWindow: PhoneWindow
    │   ├── mDecor: DecorView(根View)
    │   │   ├── StatusBar区域
    │   │   ├── ContentView(setContentView设置的布局)
    │   │   └── NavigationBar区域
    │   └── mWindowManager: WindowManagerImpl
    │       └── mGlobal: WindowManagerGlobal(进程级单例)
    │           └── addView() → 通过Binder通知WMS创建WindowState
    └── mToken: IBinder(AMS分配的Activity令牌)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 03.Activity启动模式源码分析

    # 3.1 四种启动模式的实现

    四种启动模式在源码中的处理(ActivityStarter.java):
    
    standard(LAUNCH_MULTIPLE):
      computeLaunchingTaskFlags() → 使用调用者的Task
      每次创建新的ActivityRecord
    
    singleTop(LAUNCH_SINGLE_TOP):
      deliverNewIntentLocked()中检查:
      if (top == r && top.realActivity.equals(r.realActivity)) {
          // 栈顶已有相同Activity → 调用onNewIntent,不创建新实例
          deliverNewIntentLocked(top, r.intent);
      } else {
          // 正常创建
      }
    
    singleTask(LAUNCH_SINGLE_TASK):
      getReusableIntentActivity()中查找:
      遍历所有Task,找taskAffinity匹配的Task中的目标Activity
      找到 → moveTaskToFront + clearTaskAbove + onNewIntent
      没找到 → 创建新Task或在匹配affinity的Task中创建
    
    singleInstance(LAUNCH_SINGLE_INSTANCE):
      强制创建新Task,且该Task只能有这一个Activity
      后续启动 → 复用已有实例 + onNewIntent
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    # 3.2 Intent Flags对Task的影响

    常用Intent Flags及其在AMS中的处理:
    
    FLAG_ACTIVITY_NEW_TASK:
      → 在新Task中启动(或匹配affinity的已有Task)
      → 从非Activity Context启动Activity时必须设置
    
    FLAG_ACTIVITY_CLEAR_TOP:
      → 如果目标Activity已在Task栈中,清除其上方所有Activity
      → 配合singleTask效果:清除后调onNewIntent
    
    FLAG_ACTIVITY_SINGLE_TOP:
      → 效果同singleTop启动模式(仅对栈顶生效)
    
    FLAG_ACTIVITY_CLEAR_TASK:
      → 清除整个Task栈,目标Activity作为Task的根Activity
      → 必须配合FLAG_ACTIVITY_NEW_TASK使用
    
    FLAG_ACTIVITY_NO_HISTORY:
      → Activity不会留在Task栈中
      → 离开后立即finish(不会出现在最近任务中)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    # 3.3 taskAffinity的作用原理

    taskAffinity决定了Activity更倾向于归属哪个Task。默认值为应用包名,所有Activity属于同一个Task。

    taskAffinity的使用场景:
    1. singleTask/singleInstance启动模式 → 按affinity查找已有Task
    2. FLAG_ACTIVITY_NEW_TASK → 在匹配affinity的Task中启动
    3. allowTaskReparenting=true → Activity可以从启动它的Task迁移到affinity匹配的Task
    
    示例:
    App-A的ActivityX(affinity="com.a")启动App-B的ActivityY(affinity="com.b")
      → ActivityY在App-A的Task中运行
      → 用户按Home,再启动App-B
      → 如果allowTaskReparenting=true,ActivityY会迁移到App-B的Task中
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 3.4 多实例与SingleInstance的区别

    singleTask vs singleInstance:
    
    singleTask:
      - 在匹配affinity的Task中保持单实例
      - 该Task中可以有其他Activity在它上面
      - ActivityA(singleTask) → startActivity(B) → B在同一Task中
    
    singleInstance:
      - 独占一个Task,Task中只有它自己
      - ActivityA(singleInstance) → startActivity(B) → B必须在另一个Task中
      - 最严格的单实例模式
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 04.Service原理深入分析

    # 4.1 startService与bindService对比

    两种启动方式的核心区别:
    
    startService:
      → 生命周期:onCreate → onStartCommand → (运行中) → onDestroy
      → 特点:Service与启动者无生命周期关联
      → 停止:必须显式调用stopService/stopSelf
      → 适用:后台任务,不需要与调用者交互
    
    bindService:
      → 生命周期:onCreate → onBind → (连接中) → onUnbind → onDestroy
      → 特点:Service与绑定者生命周期关联
      → 停止:所有绑定者unbind后自动销毁
      → 适用:需要与Service交互、获取返回数据
    
    两者可以混合使用:
      startService + bindService
      → 必须同时stopService + 所有unbind后才会销毁
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 4.2 Service的生命周期状态机

    // ActiveServices中Service的状态管理
    // Service的核心状态由ServiceRecord中的字段组合表示:
    
    // startRequested: 是否通过startService启动
    // bindings.size() > 0: 是否有绑定连接
    // isForeground: 是否是前台Service
    // executingStart: 是否有onStartCommand在执行
    
    // 生命周期状态转换:
    // 首次startService:
    //   bringUpServiceLocked → realStartServiceLocked
    //     → scheduleCreateService(onCreate)
    //     → sendServiceArgsLocked(onStartCommand)
    
    // 首次bindService:
    //   bringUpServiceLocked → realStartServiceLocked
    //     → scheduleCreateService(onCreate)
    //     → requestServiceBindingLocked → scheduleBindService(onBind)
    
    // stopService:
    //   stopServiceLocked → bringDownServiceIfNeededLocked
    //     → bringDownServiceLocked
    //       → scheduleStopService(onDestroy)
    //     (需确保没有绑定连接)
    
    // unbindService:
    //   unbindServiceLocked → removeConnectionLocked
    //     → 如果是最后一个连接且未被startService
    //       → bringDownServiceLocked(onDestroy)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    # 4.3 IntentService的设计原理

    IntentService(已废弃,但设计思想值得学习)通过Handler+Looper+HandlerThread实现单线程串行处理:

    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) { super(looper); }
            
            @Override
            public void handleMessage(Message msg) {
                // 在工作线程中执行
                onHandleIntent((Intent) msg.obj);
                // 执行完自动stopSelf
                stopSelf(msg.arg1);
            }
        }
        
        @Override
        public void onCreate() {
            super.onCreate();
            // 创建工作线程
            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
            thread.start();
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
        
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // 将Intent封装为Message发送到工作线程
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    # 4.4 JobIntentService与WorkManager

    IntentService的替代方案演进:
    IntentService(已废弃)
      → JobIntentService(过渡方案,也已废弃)
      → WorkManager(推荐方案)
    
    WorkManager的优势:
    1.兼容性:自动选择JobScheduler/AlarmManager/Firebase JobDispatcher
    2.约束条件:网络、电量、存储空间等约束
    3.链式任务:支持任务的依赖和串行/并行组合
    4.持久性:任务信息持久化到Room数据库,重启后恢复
    5.遵守系统限制:自动适配Doze模式和后台限制
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 05.BroadcastReceiver原理深入分析

    # 5.1 静态注册与动态注册对比

    静态注册(Manifest声明):
      注册时机:PMS扫描APK时解析Manifest
      存储位置:PMS的ComponentResolver中
      生命周期:只要应用安装就存在
      限制:Android 8.0+大部分隐式广播不再触发静态接收者
      进程:广播到达时系统会启动应用进程
    
    动态注册(代码注册):
      注册时机:调用registerReceiver时
      存储位置:AMS的mReceiverResolver中
      生命周期:与注册者生命周期绑定,需手动unregister
      限制:无隐式广播限制
      进程:必须进程存活才能接收
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 5.2 广播分发的线程模型

    广播分发的线程处理:
    AMS侧:
      BroadcastQueue在AMS的Handler线程中分发
      → 通过Binder通知目标进程
    
    应用端:
      默认在主线程接收(onReceive在主线程执行)
      → 因此onReceive中不能做耗时操作(10秒ANR限制)
    
    goAsync()机制(API 11+):
      BroadcastReceiver.PendingResult result = goAsync();
      // 在子线程中处理
      new Thread(() -> {
          // 耗时操作
          result.finish(); // 必须调用finish
      }).start();
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    # 5.3 LocalBroadcast的实现原理

    LocalBroadcastManager(已废弃)是进程内广播,不走AMS,直接在应用进程内完成匹配和分发:

    // LocalBroadcastManager内部实现
    // 本质是一个简单的Observer模式 + Handler
    class LocalBroadcastManager {
        // 注册表:Action → ReceiverRecord列表
        private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
        // 用于在主线程分发的Handler
        private final Handler mHandler;
        
        public void sendBroadcast(Intent intent) {
            // 直接在内存中匹配接收者
            ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
            // 通过Handler切到主线程分发
            mHandler.sendMessage(msg);
        }
        // handleMessage中逐个调用onReceive
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    推荐替代方案:LiveData、Flow、EventBus。

    # 5.4 有序广播的中止与修改

    // 有序广播中接收者可以中止和修改结果
    public class MyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 中止广播(后续接收者不再收到)
            abortBroadcast();
            
            // 修改结果(传递给下一个接收者)
            setResultCode(Activity.RESULT_OK);
            setResultData("modified data");
            setResultExtras(bundle);
        }
    }
    
    // AMS中有序广播的处理
    // BroadcastQueue.processNextBroadcastLocked()
    // 逐个分发,等待finishReceiver后才发给下一个
    // 如果接收者调了abortBroadcast → resultAbort=true → 停止分发
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # 06.ContentProvider原理深入分析

    # 6.1 Provider的跨进程通信机制

    ContentProvider是四大组件中唯一不通过AMS中转每次调用的组件。首次获取Provider时通过AMS,之后直接通过Binder与Provider进程通信:

    ContentProvider的通信架构:
    首次获取:
      Client → AMS.getContentProvider() → 返回IContentProvider Binder代理
    后续调用:
      Client → IContentProvider.query/insert/update/delete → Provider进程
      (不经过AMS,直接Binder通信,效率高)
    
    IContentProvider接口(Binder接口):
      query()、insert()、update()、delete()
      call()  ← 通用方法调用
      openFile() ← 文件访问
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 6.2 Cursor的数据传输原理

    ContentProvider查询返回的Cursor涉及跨进程数据传输:

    Cursor的跨进程传输机制:
    1.小数据量:直接通过Binder传输
      Provider进程创建MatrixCursor/SQLiteCursor
        → 序列化为CursorWindow(共享内存)
          → 通过Binder传递CursorWindow的文件描述符
            → Client进程通过mmap映射读取
    
    2.CursorWindow:
      基于匿名共享内存(Ashmem/memfd)
      默认大小2MB
      支持随机访问,无需全量拷贝
    
    3.大数据优化:
      CursorWindow按需加载
      Client端通过moveTo*遍历时,如果数据超出当前Window
      → 自动通过Binder请求下一批数据
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    # 6.3 ContentObserver通知机制

    ContentObserver的工作原理:
    注册:
      ContentResolver.registerContentObserver(uri, notifyForDescendants, observer)
        → ContentService.registerContentObserver()
          → 将observer注册到对应URI的观察者列表
    
    通知:
      ContentResolver.notifyChange(uri, observer)
        → ContentService.notifyChange()
          → 遍历匹配URI的所有observer
            → 通过Binder回调onChange()
              → 默认在调用线程回调
              → 可通过Handler指定回调线程
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 6.4 FileProvider的实现原理

    FileProvider是ContentProvider的子类,用于安全地共享文件:

    FileProvider的工作原理:
    1.配置file_paths.xml定义可共享的目录映射
    2.FileProvider.getUriForFile()生成content://URI
    3.授权:addFlags(FLAG_GRANT_READ_URI_PERMISSION)
    4.接收方通过ContentResolver.openInputStream(uri)读取
    
    URI格式:content://authority/path_name/file_name
      → FileProvider内部将path_name映射回实际文件路径
      → 通过openFile()返回ParcelFileDescriptor
    
    安全机制:
      - 不暴露真实文件路径
      - 可以精确控制授权范围(单个URI或URI前缀)
      - 临时授权在目标Activity/Service结束后自动撤销
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 07.组件间通信机制

    # 7.1 Intent的数据传递原理

    Intent是组件间通信的载体,其数据通过Parcel序列化经Binder传输:

    Intent的数据承载:
    Intent
    ├── mAction: String(动作)
    ├── mData: Uri(数据URI)
    ├── mType: String(MIME类型)
    ├── mComponent: ComponentName(目标组件)
    ├── mCategories: Set<String>(类别)
    ├── mFlags: int(标志位)
    └── mExtras: Bundle(附加数据)
    
    Intent的传输过程:
    Intent.writeToParcel()
      → 将所有字段序列化到Parcel
        → 通过Binder传输(Binder Driver)
          → 目标进程反序列化:Intent.readFromParcel()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 7.2 Bundle的序列化机制

    Bundle内部使用ArrayMap存储键值对,传输时通过Parcel序列化:

    Bundle支持的数据类型:
    基本类型:int、long、float、double、boolean、String
    数组类型:int[]、String[]等
    Parcelable:实现了Parcelable接口的对象
    Serializable:实现了Serializable接口的对象(性能较差)
    Bundle:嵌套Bundle
    
    序列化性能对比:
    Parcelable >> Serializable
      Parcelable:直接写入Parcel,无反射,速度快
      Serializable:使用ObjectOutputStream,大量反射,速度慢
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 7.3 Binder传输大小限制

    Binder传输限制:
    单次Binder事务大小限制:约1MB(准确值为1MB - 8KB的内核头信息)
    这个限制是单进程共享的,所有Binder调用共用这1MB缓冲区
    
    TransactionTooLargeException:
      当Intent/Bundle数据超过限制时抛出
      常见场景:
      - onSaveInstanceState保存过多数据
      - Intent附带大量数据
      - ContentProvider返回过大的Cursor
    
    防御措施:
      Intent中的数据应保持精简
      大数据使用文件、ContentProvider或共享内存传输
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 7.4 大数据传输方案

    跨进程大数据传输方案:
    1.文件传输:写入文件 → 传递文件路径/URI
    2.ContentProvider:通过Cursor或openFile传输
    3.共享内存(MemoryFile/SharedMemory):
      发送方创建SharedMemory → 写入数据
      → 通过Binder传递ParcelFileDescriptor
      → 接收方mmap映射读取
    4.Socket/Pipe:ParcelFileDescriptor.createPipe()
    5.AIDL大数据:使用ParcelFileDescriptor传输文件描述符
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    # 08.组件的进程间交互

    # 8.1 跨进程启动组件的流程

    跨进程启动Activity的完整流程:
    App-A调用startActivity(intent指向App-B的Activity)
      → Binder IPC到AMS
        → AMS检查App-B的进程是否存在
          → 不存在:通过Zygote fork新进程
            → 新进程启动 → attachApplication回调AMS
              → AMS通知新进程启动目标Activity
          → 存在:直接通知App-B进程启动Activity
        → AMS暂停App-A当前的Activity
        → App-B的Activity显示在前台
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 8.2 远程Service的Binder通信

    // AIDL定义接口
    // IMyService.aidl
    interface IMyService {
        String getData(int id);
    }
    
    // Service端实现
    public class MyService extends Service {
        private final IMyService.Stub mBinder = new IMyService.Stub() {
            @Override
            public String getData(int id) {
                return "data_" + id;
            }
        };
        @Override
        public IBinder onBind(Intent intent) { return mBinder; }
    }
    
    // Client端使用
    // bindService后在onServiceConnected中获取代理
    IMyService service = IMyService.Stub.asInterface(binder);
    String data = service.getData(123); // 跨进程Binder调用
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    # 8.3 ContentProvider的跨进程查询

    ContentProvider的跨进程查询效率较高,因为使用了CursorWindow共享内存:

    查询性能优化要点:
    1.减少返回列数:只select需要的列
    2.使用projection参数:避免select *
    3.分页查询:使用LIMIT和OFFSET
    4.避免在主线程查询:使用CursorLoader/AsyncTask
    5.批量操作:使用ContentProviderOperation.applyBatch()
    
    1
    2
    3
    4
    5
    6

    # 8.4 PendingIntent的延迟执行

    PendingIntent封装了一个Intent和一个操作(startActivity/startService/sendBroadcast),可以传递给其他进程延迟执行:

    PendingIntent的原理:
    1.创建:PendingIntent.getActivity/getService/getBroadcast
      → 通过AMS注册,返回一个IIntentSender的Binder引用
    2.传递:将PendingIntent传给其他进程(如NotificationManager、AlarmManager)
    3.执行:其他进程调用PendingIntent.send()
      → 通过IIntentSender.send() → AMS执行原始操作
      → 以创建者的身份和权限执行(不是调用者的权限)
    
    安全意义:
      PendingIntent授予了目标进程以你的身份执行指定操作的能力
      必须谨慎使用,指定FLAG_IMMUTABLE防止被篡改(Android 12+强制)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    # 09.组件安全与权限控制

    # 9.1 组件的exported属性

    exported属性决定组件是否可被其他应用访问:
    true  → 其他应用可以启动/绑定/发送
    false → 仅同一应用(或相同UID)可访问
    
    默认值规则:
    - 声明了<intent-filter> → 默认exported=true
    - 未声明<intent-filter> → 默认exported=false
    - Android 12+:targetSdkVersion>=31的应用必须显式声明exported
    
    安全建议:
    - 不需要外部访问的组件必须设置exported=false
    - 需要外部访问的组件应配合permission保护
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    # 9.2 Permission保护组件

    <!-- 定义权限 -->
    <permission android:name="com.example.MY_PERMISSION"
        android:protectionLevel="signature" />
    
    <!-- 使用权限保护组件 -->
    <activity android:name=".SecureActivity"
        android:exported="true"
        android:permission="com.example.MY_PERMISSION" />
    
    <provider android:name=".MyProvider"
        android:authorities="com.example.provider"
        android:readPermission="com.example.READ"
        android:writePermission="com.example.WRITE" />
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    AMS在启动组件前会调用PMS检查调用者是否具有所需权限。

    # 9.3 签名级权限的应用

    signature级别权限只有与定义者相同签名的应用才能获得,适用于同一开发者的多个应用之间的安全通信。

    # 9.4 Android 12的安全增强

    Android 12+的组件安全增强:
    1.exported必须显式声明(targetSdk>=31)
    2.PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE
    3.精确的Intent匹配:限制隐式Intent的包可见性
    4.后台启动限制:禁止后台应用启动Activity和前台Service
    
    1
    2
    3
    4
    5

    # 10.总结与面试要点

    # 10.1 四大组件对比总结

    四大组件对比:
    ┌──────────┬────────────┬───────────┬────────────┬───────────┐
    │          │ Activity    │ Service   │ Broadcast  │ Provider  │
    ├──────────┼────────────┼───────────┼────────────┼───────────┤
    │ 用途      │ UI交互     │ 后台任务   │ 事件通知    │ 数据共享   │
    │ 有无界面  │ 有          │ 无        │ 无          │ 无        │
    │ 通信方式  │ Intent     │ Intent/   │ Intent     │ URI       │
    │          │            │ Binder    │            │           │
    │ 管理者    │ ATMS       │ AMS       │ AMS        │ AMS       │
    │ 跨进程    │ AMS中转    │ AMS/Binder│ AMS广播    │ 直接Binder │
    │ 生命周期  │ 7个回调    │ 按启动方式 │ onReceive  │ onCreate  │
    └──────────┴────────────┴───────────┴────────────┴───────────┘
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    # 10.2 高频面试题解析

    Q:Activity的生命周期由谁驱动? A:由AMS(ATMS)驱动。AMS通过Binder向应用端发送ClientTransaction,TransactionExecutor计算状态路径并逐个执行生命周期回调。

    Q:startService和bindService的区别? A:startService启动后Service与调用者无关联,需显式stopService停止。bindService将Service与调用者生命周期关联,所有绑定者unbind后自动销毁。两者可混合使用,需同时满足两个停止条件才销毁。

    Q:静态广播和动态广播的区别? A:静态在PMS注册(Manifest),应用未启动也能接收(Android 8.0+受限)。动态在AMS注册(代码),需进程存活。动态注册走并行队列(快),静态走有序队列(慢)。

    Q:ContentProvider为什么在Application.onCreate之前初始化? A:设计上Provider应在应用启动后立即可用(其他进程可能在等待)。AMS在attachApplicationLocked中先让应用安装Provider,再调callApplicationOnCreate。这也是很多库(如LeakCanary)利用Provider实现自动初始化的原因。

    # 10.3 最佳实践建议

    组件使用最佳实践:
    1.Activity:避免在onResume/onPause中做耗时操作,影响切换流畅度
    2.Service:优先使用WorkManager替代后台Service,遵守后台限制
    3.Broadcast:优先使用动态注册,应用内通信使用LiveData/Flow
    4.Provider:使用FileProvider分享文件,避免暴露真实路径
    5.通用:组件间传递的数据要精简,避免TransactionTooLargeException
    
    1
    2
    3
    4
    5
    6
    上次更新: 2026/06/10, 11:13:41
    Activity启动原理
    AMS与组件管理

    ← Activity启动原理 AMS与组件管理→

    最近更新
    01
    信号崩溃快速排查
    06-15
    02
    CoreDump破案
    06-15
    03
    perf火焰图实战
    06-15
    更多文章>
    Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式