iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
Software Development

AI 時代的 Android Engineer:30 天打造我的 AI 開發工作流系列 第 17 篇

Day 17 - Process Death之後,真的要把整個畫面State存起來嗎?

  • 分享至 

  • xImage
  •  

昨天整理到 Process Death 時,提到了 SavedStateHandle。

如果 ViewModel 在 Process 被殺掉之後也會消失,那很直覺就會想到:

是不是重要的 State 都應該放進 SavedStateHandle?

但仔細想又會發現,如果一個畫面的 State 很大,裡面有 API Response、List、Loading、Error、選擇結果,全部保存好像也不太合理。

所以今天想繼續昨天的問題:

Process Death 之後,到底什麼東西需要「保存」,什麼東西其實重新取得就好?

先把「畫面恢復」拆成兩件事

假設有一個搜尋頁面,目前畫面是:

keyword = "Android"
category = "技術書"
sort = "最新"

搜尋結果
↓
50 筆資料

如果 Process 被系統回收,之後使用者回到這個畫面,我希望他看到跟剛才差不多的內容。

第一個直覺可能是:

把整個畫面 State 保存
↓
回來全部還原

但其實不一定需要。

因為這個畫面裡有兩種不同性質的資料:

使用者決定的資料
keyword
category
sort

可以重新取得的資料
搜尋結果

真正無法憑空知道的,是使用者剛才做了哪些選擇。

至於搜尋結果,只要條件還在,就有機會重新 Request。

所以恢復畫面不一定等於:

把畫面所有資料完整保存。

也可能是:

保存足以重新建立畫面的最小資訊。

SavedStateHandle 比較像是「重建線索」

例如:

class SearchViewModel(
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    var keyword: String
        get() = savedStateHandle["keyword"] ?: ""
        set(value) {
            savedStateHandle["keyword"] = value
        }
}

Process 被重新建立後,我不需要從 SavedStateHandle 拿回完整搜尋結果。

只要拿回:

keyword = Android

再重新:

keyword
↓
Repository
↓
API
↓
Search Result
↓
UI

畫面就有機會重新建立。

所以我現在會把 SavedStateHandle 理解成:

保存「重新建立目前狀態所需要的資訊」,而不是另一個資料庫。

那哪些 State 值得保存?

這時就可以再細分。

例如:

搜尋關鍵字
選中的分類
目前選擇的商品 ID
表單填到一半的內容
目前頁面的 Navigation argument

這些資料有一個共同點:

如果它消失,我很難單純從後端或資料庫重新推導回來。

因為它們通常代表使用者目前正在做的事情。

但另外一些 State:

商品名稱
商品圖片
搜尋結果
會員資料
訂單內容

很多原本就有真正的資料來源。

例如:

productId
↓
Repository
↓
API / Database
↓
Product

這時比起保存整個 Product,有時候保存:

productId

反而比較合理。

Source of Truth 在哪裡,會影響我要保存什麼

這件事其實又回到前幾天一直在看的 State Ownership。

假設:

Room
↓
Repository
↓
ViewModel
↓
UI

Room 才是這筆資料真正的來源。

ViewModel 裡的資料只是目前畫面使用的版本。

如果 Process Death:

ViewModel 消失

不代表資料真的消失。

新的 ViewModel 可以:

Repository
↓
Room
↓
重新取得

所以這份資料沒有必要為了 Process Death,再另外完整塞進 SavedStateHandle。

反過來,如果是:

使用者剛剛選了哪個 Tab

這件事情可能沒有任何 Repository 可以重新告訴我。

那它就比較接近需要恢復的 UI State。

所以判斷 State 要不要保存時,我覺得可以多問一題:

這份資料真正的 Source of Truth 在哪裡?

有些 State 甚至根本不需要保存

還有第三種。

例如:

isLoading = true

Process Death 之前正在 Loading。

那重新建立之後,我真的需要把:

isLoading = true

恢復嗎?

不一定。

因為新的流程可能是:

重新建立
↓
重新 Request
↓
自然進入 Loading
↓
取得資料
↓
Success

isLoading 本身其實是其他流程產生的結果。

同樣的:

errorMessage
buttonEnabled
formattedPrice

有些 State 都可能是可以重新計算或重新產生的。

如果原始資料還在,就不一定需要把「計算結果」也保存一份。

這讓 State 又可以再拆成:

需要保存的原始資訊
↓
重新取得的資料
↓
可以重新計算的 UI State

如果全部都存,反而可能出現兩份真相

假設 Repository 已經有一份商品資料:

Repository
Product(price = 100)

但 SavedStateHandle 又保存:

Product(price = 90)

Process 恢復之後就會出現一個問題:

到底哪一份才是真的?

如果 Server 上的價格已經更新,舊 State 又被完整恢復,就可能把過期資料重新顯示出來。

所以「能不能保存」跟「應不應該保存」其實是不同問題。

有真正資料來源的資料,通常應該回去找真正的資料來源。

而不是讓每一層都保存一份自己的版本。

我開始比較能分清楚三種東西

如果把 Day 15、16、17 放在一起,目前我會先把 State 粗略分成:

1. 需要恢復的 State

例如:
搜尋關鍵字
使用者選擇
輸入中的內容

↓

2. 可以重新取得的資料

例如:
API Response
Room 裡的資料
Repository 管理的資料

↓

3. 可以重新計算的 State

例如:
formattedText
buttonEnabled
部分 Loading 狀態

第一種才比較需要認真考慮:

Process Death 後我要怎麼把它找回來?

第二種要想的是:

真正的資料來源在哪裡?

第三種則要問:

我是不是根本不需要保存它?

所以 SavedStateHandle 不是 State 的備份區

昨天講到:

ViewModel
→ 撐過 Configuration Change

SavedStateHandle
→ 幫助 Process Death 後恢復

Room
→ 長期保存

這樣分類雖然方便,但還是太粗。

因為真正做功能時,不是看到:

Process Death

就把 ViewModel 裡所有東西複製到 SavedStateHandle。

更重要的應該是先找:

哪些資訊是使用者剛剛產生的?
↓
哪些資料本來就有 Source of Truth?
↓
哪些 State 可以重新推導?
↓
最後才決定需要保存什麼

所以現在如果要我重新想「畫面狀態恢復」,我會比較傾向這個順序:

State 消失
↓
能重新取得嗎?
├─ Yes → 從 Source of Truth 重新取得
└─ No
   ↓
能重新計算嗎?
├─ Yes → 重新計算
└─ No
   ↓
考慮保存恢復所需的最小資訊

這樣看下來,真正需要保存的東西可能比想像中少很多。

狀態恢復的目標,不一定是把死亡前的記憶體完整複製回來,而是保留足夠的資訊,讓畫面能重新建立。

從 Singleton、ViewModel、Process Death 一路看到這裡,我覺得自己其實一直在拆同一件事:

State 不只是「放在哪裡」,還要知道它從哪裡來、誰擁有它,以及消失之後應該保存、重取,還是重新計算。

這幾個問題先想清楚,再決定要不要用 SavedStateHandle,好像就比「重要 State 都存起來」更有方向。


上一篇
Day 16 - 畫面重建、Process Death、App被關掉,其實不是同一件事
系列文
AI 時代的 Android Engineer:30 天打造我的 AI 開發工作流 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言