一、 一個 iOS 開發者,把我問住了
上週,一個剛從 iOS 轉過來的同事問我:
「Android 為什麼不喜歡用介面回呼傳結果? iOS 那邊 delegate、closure 不就挺好的?」
我第一反應是:
「因為 Activity 可能會被銷毀。」
但說完我自己都覺得不夠到位。
這話沒錯,但只解釋了「現象」,沒解釋「為什麼會這樣」。
後來我們從 Activity 聊到 Binder,從生命週期聊到系統架構,他來了一句:
「原來這不是 API 習慣問題,這是系統底層設計不一樣。」
對,就是這個點,這個和 iOS 設計不太一樣。
先把問題抽象一下:
為什麼 Android Activity 通訊不用介面,而用
onActivityResult?
很多人會這麼答:
這些都對,但都停在「現象層」。
真正的問題是:
Android 整個系統,根本就不是為「物件參照通訊」設計的。
你寫的這段程式碼,其實隱含了一個前提:

👉 這件事本質上是:
A 和 B 共享一塊記憶體,並且持有同一個物件參照
這在單程序世界是成立的。
但問題來了
Android 的三大通訊基石:
它們有一個共同點:
全部是「訊息」,不是「參照」
換句話說:
模型特徵 介面 callback 共享物件參照(共享記憶體) Android 元件通訊 傳送訊息(序列化資料)這不是 Activity 的限制,這是整個系統的選擇。
在 Android 裡,Activity 的生殺大權在系統手裡(ActivityManagerService)。
這意味著什麼?
👉 A 活著,不是你說了算
經典場景:
A → 開啟 B
↓
使用者接電話 / 切到背景
↓
系統記憶體緊張 → 殺掉 A(B 還活著)
↓
使用者回到 B,點擊完成
如果你用介面:
B → callback.onResult()
↓
💥 A 已經沒了
問題不是「可能 crash」,而是:
這個呼叫在語意上已經失效了
既然:
那就只剩一個解法:
只傳遞「可序列化的資料」,由系統負責中轉
這就是 onActivityResult 的本質。
來看真實模型:
A 呼叫 startActivityForResult
↓
系統記錄(Token + requestCode)
↓
B 執行(A 可以隨時被殺)
↓
B setResult + finish
↓
系統查記錄
↓
如果 A 不在 → 重建 A
↓
分發結果(onActivityResult)
注意三個關鍵點:
系統只認 Token,不認參照。
onActivityResult本質上是一次系統分發事件 👉 不是函式回呼
requestCode 的意義是:
在沒有上下文的情況下,恢復語意
因為它解決的是另一個問題。
在 iOS 裡,ViewController 由導覽堆疊管理:
UINavigationController
└── [A, B]
這意味著:
✅ 只要 B 還在,A 一定還在
所以:
delegate?.onResult()
是安全的。
舉兩個例子:
👉 這些場景:
本質上:
一旦跨程序,iOS 也必須放棄物件參照模型
Android iOS
生命週期控制 系統(不可控) 導覽堆疊(可控)
通訊模型 訊息驅動 參照驅動(單程序)
跨程序能力 預設支援 需要系統橋接
回呼本質 生命週期分發 物件呼叫
現在我們用:
registerForActivityResult { }
看起來像 callback。
但本質上:
底層還是 requestCode + 系統分發
它做的只是:
👉 這是「體驗優化」,不是「模型改變」。
Android 不用介面通訊,不是因為 Activity 會被銷毀,而是因為整個系統是「訊息驅動 + 跨程序優先」的架構,天然不支援物件參照語意。(筆者認為這個設計初衷是好的,但是太重了,尤其對於應用內的通訊)