为什么 Android 不用接口做 Activity 通信?

1 阅读4分钟

一、一个 iOS 开发者,把我问住了

上周,一个刚从 iOS 转过来的同事问我:

“Android 为啥不喜欢用接口回调传结果? iOS 那边 delegate、closure 不就挺好吗?”

我第一反应是:

“因为 Activity 可能被销毁。”

但说完我自己都觉得不够到位。

这话没错,但只解释了“现象”,没解释“为什么会这样”。

后来我们从 Activity 聊到 Binder,从生命周期聊到系统架构,他来了一句:

“原来这不是 API 习惯问题,这是系统底层设计不一样。”

对,就是这个点,这个和iOS设计不太一样。


二、你以为这是“用法问题”,其实是“设计问题”

先把问题抽象一下:

为什么 Android Activity 通信不用接口,而用 onActivityResult

很多人会这么答:

  • Activity 可能被销毁
  • 防止内存泄漏

这些都对,但都停在“现象层”。

真正的问题是:

Android 整个系统,根本就不是为“对象引用通信”设计的。


三、接口通信,本质是“共享内存模型”

你写的这段代码,其实隐含了一个前提:

image.png

👉 这件事本质上是:

A 和 B 共享一块内存,并且持有同一个对象引用

这在单进程世界是成立的。

但问题来了


四、Android 是“消息驱动系统”,不是“对象驱动系统”

Android 的三大通信基石:

  • Intent
  • Binder
  • Bundle

它们有一个共同点:

全部是“消息”,不是“引用”

换句话说:

模型特征
接口 callback共享对象引用(共享内存)
Android 组件通信发送消息(序列化数据)

这不是 Activity 的限制,这是整个系统的选择。


五、第一个致命约束:组件不归你管

在 Android 里,Activity 的生杀大权在系统手里(ActivityManagerService)。

这意味着什么?

👉 A 活着,不是你说了算

经典场景:

A → 打开 B
↓
用户接电话 / 切后台
↓
系统内存紧张 → 杀掉 AB 还活着)
↓
用户回到 B,点击完成

如果你用接口:

B → callback.onResult()
        ↓
💥 A 已经没了

问题不是“可能 crash”,而是:

这个调用在语义上已经失效了


六、所以 Android 只能选择一条路

既然:

  • 不能依赖对象还活着
  • 不能传递对象引用

那就只剩一个解法:

只传递“可序列化的数据”,由系统负责中转

这就是 onActivityResult 的本质。


七、你以为它是 callback,其实它是“系统协议”

来看真实模型:

A 调用 startActivityForResult
        ↓
系统记录(Token + requestCode)
        ↓
B 执行(A 可以随时被杀)
        ↓
B setResult + finish
        ↓
系统查记录
        ↓
如果 A 不在 → 重建 A
        ↓
分发结果(onActivityResult)

注意三个关键点:

1️⃣ 不存对象,只存“标识”

系统只认 Token,不认引用。


2️⃣ 回调的不是对象,是“生命周期事件”

onActivityResult 本质是一次系统分发事件 👉 不是函数回调


3️⃣ 整个过程是“无状态设计”

requestCode 的意义是:

在没有上下文的情况下,恢复语义


八、iOS 为什么可以用接口?

因为它解决的是另一个问题。

在 iOS 里,ViewController 由导航栈管理:

UINavigationController
    └── [A, B]

这意味着:

只要 B 还在,A 一定还在

所以:

delegate?.onResult()

是安全的。


九、但 iOS 一旦跨进程,也“变成 Android”

举两个例子:

  • 相机(UIImagePickerController)
  • 分享(UIActivityViewController)

👉 这些场景:

  • 不再使用 delegate 持有引用
  • 而是使用系统回调 / completion

本质上:

一旦跨进程,iOS 也必须放弃对象引用模型


十、本质差异,不在 API,在“控制权”

AndroidiOS
生命周期控制系统(不可控)导航栈(可控)
通信模型消息驱动引用驱动(单进程)
跨进程能力默认支持需要系统桥接
回调本质生命周期分发对象调用

十一、现代 API 只是“糖”

现在我们用:

registerForActivityResult { }

看起来像 callback。

但本质上:

底层还是 requestCode + 系统分发

它做的只是:

  • 生命周期绑定
  • 类型安全
  • API 收敛

👉 这是“体验优化”,不是“模型改变”。


十二、总结

Android 不用接口通信,不是因为 Activity 会被销毁,而是因为整个系统是“消息驱动 + 跨进程优先”的架构,天然不支持对象引用语义。(笔者认为这个设计初衷是好的,但是过重了,尤其对于应用内的通信)

  • 生命周期不可靠 → 不能依赖对象存在
  • 跨进程 → 引用无法传递
  • 系统调度 → 回调必须可恢复
  • 理解了这一点,你就知道为什么应用内ViewModel + Flow 是正确答案——它把"状态"从 Activity 里抽出来,放到了不受系统生杀权影响的地方。