iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Software Development

從 Fragment 到 Compose — 老 Android App 重寫的架構取捨系列 第 15 篇

Day 15|拖曳排序:樂觀更新與回滾

  • 分享至 

  • xImage
  •  

動筆前先答(兩題)

1.【模擬面試追問|持久化與離線】 舊的排序畫面有一個開關:打開時,每放下一筆任務,就把新順序送給後端,後端會重排其他任務再回傳;等待回應的期間,整個列表鎖住不能拖。新版想改成樂觀更新:放下的當下就更新畫面,請求在背景送,失敗就回滾。面試官順著這個設計往下追問:

  • 使用者連續拖了三次,第 1 次的請求還沒回來,他就拖了第 2、3 次。結果第 2 次失敗,第 1、3 次成功。「回滾」要回到哪個順序?為了做到這件事,你的程式要記住什麼?
  • 後端成功後回傳的是「它重排過的完整順序」,跟使用者畫面上的順序不一樣。畫面要照誰的?如果回應到達時,使用者正在拖第 4 次呢?
  • 請求送出後、回應還沒到,App 就被系統回收了。重開之後,畫面該顯示哪個順序?

我的回答:
我覺得回滾要回到第 3 次的成功回應,從新。為了達到這目的,需要記住所有請求的結果(回應是否失敗)。以及請求的順序。

後端是唯一事實來源,畫面要照後端成功回傳的重排順序。如果回應到達時,使用者正在拖第 4 次,則優先更新列表,放棄使用者的第 4 次拖移排序。

App 被系統回收後,背景執行緒取消了。重開之後,畫面該顯示請求送出時的原本列表順序。

2.【預測再驗證|UI 與版型】 用 LazyColumn 做拖曳排序。把第 1 筆拖到第 3 筆的位置時,ViewModel 交換清單元素,發出一份新的清單。每一列裡有一個「展開備註」的狀態:

@Composable
fun TaskRow(task: Task) {
    var expanded by remember { mutableStateOf(false) }
    // 點一下切換 expanded,展開時多顯示一段備註
}

// A:沒有 key
LazyColumn { items(tasks) { task -> TaskRow(task) } }

// B:用任務 id 當 key
LazyColumn { items(tasks, key = { it.id }) { task -> TaskRow(task) } }

使用者先展開第 1 筆的備註,再把它拖到第 3 筆的位置。A、B 各自拖完之後,展開的是畫面上的哪一列?在列上加了 Modifier.animateItem() 時,A、B 有沒有移動的動畫?先寫下預測與理由,再用 Compose UI 測試(或 Preview 的互動模式)驗證。最後判斷:key 用任務 id 就夠了嗎?如果同一張訂單可能在列表出現兩次(例如取件、送件各一筆),key 要怎麼定?

我的回答:
(待補)


上一篇
Day 14|拆一個 1,700 行的 ViewModel:`combine` 取代屏障
下一篇
Day 16|Use case 層要不要:排序與篩選規則該放哪裡
系列文
從 Fragment 到 Compose — 老 Android App 重寫的架構取捨 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言