為什麼 Android 不用介面做 Activity 通訊?

一、 一個 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
↓
使用者接電話 / 切到背景
↓
系統記憶體緊張 → 殺掉 A(B 還活著)
↓
使用者回到 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,在「控制權」

Android iOS
生命週期控制 系統(不可控) 導覽堆疊(可控)
通訊模型 訊息驅動 參照驅動(單程序)
跨程序能力 預設支援 需要系統橋接
回呼本質 生命週期分發 物件呼叫


十一、現代 API 只是「糖」

現在我們用:

registerForActivityResult { }

看起來像 callback。

但本質上:

底層還是 requestCode + 系統分發

它做的只是:

  • 生命週期綁定
  • 型別安全
  • API 收斂

👉 這是「體驗優化」,不是「模型改變」。


十二、總結

Android 不用介面通訊,不是因為 Activity 會被銷毀,而是因為整個系統是「訊息驅動 + 跨程序優先」的架構,天然不支援物件參照語意。(筆者認為這個設計初衷是好的,但是太重了,尤其對於應用內的通訊)

  • 生命週期不可靠 → 不能依賴物件存在
  • 跨程序 → 參照無法傳遞
  • 系統調度 → 回呼必須可恢復
  • 理解了這一點,你就知道為什麼應用內 ViewModel + Flow 是正確答案——它把「狀態」從 Activity 裡抽出來,放到了不受系統生殺大權影響的地方。

原文出處:https://juejin.cn/post/7638897090145075246


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝16   💬11   ❤️1
542
🥈
alicec
📝1   ❤️2
77
🥉
我愛JS
💬2  
7
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登