Jetpack Compose 面試必考題:2025年你不能忽略的關鍵知識點
[# 🚀 Jetpack Compose 面試問題 2025年不容忽視!如果你最近在準備 Android 求職面談,Jetpack Compose 算是蠻多人討論的領域。從以前的 XML 慢慢轉向 Compose,好像不少公司都開始重視這塊,常常會在面試時被問到。今天這個主題,大概算 Android 面試系列裡的第六篇吧,主要整理一些蠻常見又容易出現的 Jetpack Compose 問題。從狀態管理、recomposition 到一些小細節,內容都會拆解得比較簡單一點,可能能幫助你在面談時多一點信心啦!💡🔥 準備好了嗎?那就直接來看看吧!🚀
1️⃣ **什麼是 Jetpack Compose 裡面的 `remember`?]
1️⃣ **什麼是 Jetpack Compose 裡面的 `remember`?]
原文出處: https://www.kantti.net/tw/column/2296/2025-mid-level-android-developer-career-plan-interview-questio
記住這個就對了!深入解析 Jetpack Compose 的 remember 用法
在 Jetpack Compose 裡,`remember`這東西有點像是把某個值暫時放在記憶裡。畫面重繪的時候,它不會馬上消失,差不多可以讓資料撐住一段時間。例如有人寫一個簡單的計數器,那個 `count` 變數就算介面動一下,也還會留著,大概就這意思啦。
舉例來說,有人寫過類似下面這樣的元件:
只要點那顆按鈕,畫面可能會重新組合,但那個數字通常都還在。不過,其實這裡也不是什麼萬無一失的方法,畢竟記憶體如果被清掉(像是裝置旋轉或其他意外),好像還是可能歸零。
再說到 `rememberSaveable`,情況又有點不同。有些人注意到,如果只是用 `remember`,當手機螢幕方向改變之後,那些資料大概就沒了;可是換成 `rememberSaveable` 的話,好像就比較容易撐住。反正就是你把它想成「能夠替某些特定狀況(像螢幕旋轉)多留一手」那種感覺吧。
舉兩個常見寫法好了:
跟
前者好像比較適合短暫、臨時性的狀態,不太怕一下子丟掉;後者則偏向你希望即使遇到一些小變化(例如轉動手機),那個值也能繼續活著。
何時該選哪一種?其實大家用起來會根據需求調整,不會有一定規則,只能說大部分人在需要穩定保存狀態時,可能就傾向用 `rememberSaveable`。但這些都不是絕對,大約如此。
舉例來說,有人寫過類似下面這樣的元件:
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
只要點那顆按鈕,畫面可能會重新組合,但那個數字通常都還在。不過,其實這裡也不是什麼萬無一失的方法,畢竟記憶體如果被清掉(像是裝置旋轉或其他意外),好像還是可能歸零。
再說到 `rememberSaveable`,情況又有點不同。有些人注意到,如果只是用 `remember`,當手機螢幕方向改變之後,那些資料大概就沒了;可是換成 `rememberSaveable` 的話,好像就比較容易撐住。反正就是你把它想成「能夠替某些特定狀況(像螢幕旋轉)多留一手」那種感覺吧。
舉兩個常見寫法好了:
var count by remember { mutableStateOf(0) }
跟
var count by rememberSaveable { mutableStateOf(0) }
前者好像比較適合短暫、臨時性的狀態,不太怕一下子丟掉;後者則偏向你希望即使遇到一些小變化(例如轉動手機),那個值也能繼續活著。
何時該選哪一種?其實大家用起來會根據需求調整,不會有一定規則,只能說大部分人在需要穩定保存狀態時,可能就傾向用 `rememberSaveable`。但這些都不是絕對,大約如此。

remember vs rememberSaveable:哪個該用在什麼情境?
有些人會在寫 Jetpack Compose 的時候,常常聽到什麼「remember」跟「rememberSaveable」,其實這兩個差別還蠻有趣的。像是,如果只是要記住一點臨時的小資料,可能有人就用前面那個;可是如果遇到螢幕橫豎切換、應用程式突然被系統回收又重啟,好像「remember」就派不上什麼大用場了。
至於「rememberSaveable」到底怎麼讓資料活下來?這個說法一直都不太一致。有工程師說它是靠著 Android 裡面那種很常見的 Bundle 儲存機制,差不多就是那種 onSaveInstanceState 會碰到的東西吧,把你塞進去的內容通通丟進一個類似行李箱的小包包裡。萬一哪天畫面轉了一下或者 App 被暫停再打開,它又能把這些東西撿回來。不過詳細流程倒也沒有誰真的全弄懂,大致上就是先保存、再還原,感覺很像做備份一樣。
其實每次遇到畫面旋轉、甚至偶爾手機資源緊張跑去殺掉 app,那些用「rememberSaveable」記下來的值,多半都還找得到。當然啦,也不是說百分百沒例外,但至少比單純用「remember」多了點安全感。反正只要沒什麼極端狀況,大概都能正常恢復。至於那些細節——Bundle 到底塞了啥、有沒有侷限——可能只有深入研究 Android 底層的人才講得清楚。我們一般開發者,好像也就是知道它背後用了傳統儲存方式,這樣就夠了吧。
至於「rememberSaveable」到底怎麼讓資料活下來?這個說法一直都不太一致。有工程師說它是靠著 Android 裡面那種很常見的 Bundle 儲存機制,差不多就是那種 onSaveInstanceState 會碰到的東西吧,把你塞進去的內容通通丟進一個類似行李箱的小包包裡。萬一哪天畫面轉了一下或者 App 被暫停再打開,它又能把這些東西撿回來。不過詳細流程倒也沒有誰真的全弄懂,大致上就是先保存、再還原,感覺很像做備份一樣。
其實每次遇到畫面旋轉、甚至偶爾手機資源緊張跑去殺掉 app,那些用「rememberSaveable」記下來的值,多半都還找得到。當然啦,也不是說百分百沒例外,但至少比單純用「remember」多了點安全感。反正只要沒什麼極端狀況,大概都能正常恢復。至於那些細節——Bundle 到底塞了啥、有沒有侷限——可能只有深入研究 Android 底層的人才講得清楚。我們一般開發者,好像也就是知道它背後用了傳統儲存方式,這樣就夠了吧。
rememberSaveable 背後的魔法:數據是如何被保存下來的?
有時候在寫介面相關的東西,資料存取那邊也會有點眉角。比方說你可能遇過這種自動儲存機制——像如果只是在處理一些數字、文字或者說簡單的資料型態,大致上不用太煩惱,系統自己就會幫忙記著。舉個例子好了,有個地方用到一個計數器,寫法大概像這樣:
其實主要就是因為整數本身很單純,所以好像不用多想什麼。
可是一旦碰上比較複雜的人物啊、設定檔這類東西,就沒辦法完全靠內建的方式。通常這時候得自己定義某種儲存與回復方法(Saver),才能讓那些內容在畫面旋轉或其他狀況下還保留著。例如說,如果哪天要保存一個使用者資訊,大約會長這樣:
裡頭那個UserSaver,大致是告訴系統該怎麼把User物件塞進去又拿出來。
再仔細想,其實背後這些值都被存在某種SavedInstanceState裡面,也就是讓App在意外關掉或轉螢幕時不至於全部歸零。有些朋友覺得,只要是普通型別就能自動搞定,但如果遇到特別結構的資料,再麻煩用Saver幫一下手,比較不容易丟失內容。不過效果怎麼樣嘛,可能還是得看狀況才知道啦。
var count by rememberSaveable { mutableStateOf(0) }
其實主要就是因為整數本身很單純,所以好像不用多想什麼。
可是一旦碰上比較複雜的人物啊、設定檔這類東西,就沒辦法完全靠內建的方式。通常這時候得自己定義某種儲存與回復方法(Saver),才能讓那些內容在畫面旋轉或其他狀況下還保留著。例如說,如果哪天要保存一個使用者資訊,大約會長這樣:
@Composable
fun UserProfile() {
val user = rememberSaveable(stateSaver = UserSaver) { mutableStateOf(User("John", 25)) }
}
裡頭那個UserSaver,大致是告訴系統該怎麼把User物件塞進去又拿出來。
再仔細想,其實背後這些值都被存在某種SavedInstanceState裡面,也就是讓App在意外關掉或轉螢幕時不至於全部歸零。有些朋友覺得,只要是普通型別就能自動搞定,但如果遇到特別結構的資料,再麻煩用Saver幫一下手,比較不容易丟失內容。不過效果怎麼樣嘛,可能還是得看狀況才知道啦。

重組(Recomposition)是什麼?讓你的 UI 自動更新的秘密
有時候在 Jetpack Compose 裡,畫面變動其實跟「重組」這件事脫不了關係。說到 Recomposition,好像就是狀態一改變,某些 Composable 函式又會被重新執行。通常這種更新不會直接波及全部 UI,大致上只有那些真的有用到發生變化的資料的部分才會再跑一次,這樣可以省點效能。不過也不是每次都那麼精確,有時候可能多重了一小段。
觸發重組的方法好像也沒有固定幾種,只要跟狀態扯上關係的東西——比方說 mutableStateOf、LiveData 或 StateFlow 之類的東西——大概就有可能引起畫面更新。如果你把新的參數傳進一個 Composable,也常見會發生重繪。舉個簡單例子好了:
像上面這段,每次按下按鈕,那個 count 數字往上加個一兩下,其實 Text 那塊顯示用的地方就會跟著跑一次更新。有的人覺得這種方式還挺直觀的,不過如果寫得太複雜,也許偶爾會有預期外的小細節需特別留意。
觸發重組的方法好像也沒有固定幾種,只要跟狀態扯上關係的東西——比方說 mutableStateOf、LiveData 或 StateFlow 之類的東西——大概就有可能引起畫面更新。如果你把新的參數傳進一個 Composable,也常見會發生重繪。舉個簡單例子好了:
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count") // 只要 count 動了,這裡就換新內容
}
}
像上面這段,每次按下按鈕,那個 count 數字往上加個一兩下,其實 Text 那塊顯示用的地方就會跟著跑一次更新。有的人覺得這種方式還挺直觀的,不過如果寫得太複雜,也許偶爾會有預期外的小細節需特別留意。
什麼情況會觸發重組?掌握這些就能避免效能浪費
有時候在 Jetpack Compose 裡頭,畫面重繪的情況比想像中還要頻繁,不少人會覺得奇怪。有人說,要是能把變動的東西用 remember 記起來,或許能減少一點重複工作。有些開發者好像傾向用 rememberSaveable,那東西碰到手機旋轉、切換深色模式什麼的,好像也比較不會讓狀態整個重來。
其實還有件事,有不少人提過,參數如果經常送進新的物件,就算內容沒改,看起來系統還是當作全新東西再處理一次,好像這樣就容易出現多餘的重新組合。於是大家偶爾會提醒,如果可以盡量傳一些內容穩定不變的參數,也許比較能降低意外刷新。
另外,在列表那種場景下(比如 LazyColumn),有人建議給每個項目設一個 key,好讓系統認得哪些資料其實沒怎麼動過。據說這樣也可能減少一部分莫名其妙的運算。不過效果似乎沒有百分之百保證,畢竟遇到複雜互動或大量資料時,難免還是會有漏網之魚。
總之,這幾種方法聽說在不少專案裡都有被嘗試應用。實際上是否明顯改善,就看情境和資料規模,有些團隊觀察到成效,但偶爾也有人反映差異沒想像大。
其實還有件事,有不少人提過,參數如果經常送進新的物件,就算內容沒改,看起來系統還是當作全新東西再處理一次,好像這樣就容易出現多餘的重新組合。於是大家偶爾會提醒,如果可以盡量傳一些內容穩定不變的參數,也許比較能降低意外刷新。
另外,在列表那種場景下(比如 LazyColumn),有人建議給每個項目設一個 key,好讓系統認得哪些資料其實沒怎麼動過。據說這樣也可能減少一部分莫名其妙的運算。不過效果似乎沒有百分之百保證,畢竟遇到複雜互動或大量資料時,難免還是會有漏網之魚。
總之,這幾種方法聽說在不少專案裡都有被嘗試應用。實際上是否明顯改善,就看情境和資料規模,有些團隊觀察到成效,但偶爾也有人反映差異沒想像大。

五招教你避開不必要的重組,提升 Compose 應用效能
為什麼現在越來越多人開始討論用 Compose 取代過去那種 XML 寫法?這當中,或許有人會說界面開發終於不用再一直切換檔案,還有一部分人覺得寫起來靈活度高了不少。看起來像是把 UI 跟邏輯綁在一起的感覺,對某些開發者來說好像比較直觀。以前那種 XML 靜態描述,每次想改個小地方,不只是 layout 要動手,程式碼那頭也常常要跟著調整,好像挺容易出現同步問題。
大概從某個時間點開始,有人注意到 Compose 用聲明式寫法,把元件組合方式弄得有點類似拼積木,減少了重複處理畫面狀態的機會。還聽說如果畫面結構一變動,以前在 XML 那套需要重新安排層級、ID 什麼的,用 Compose 好像彈性就大很多。而且狀態管理這件事,在新的做法下被包裝得簡單不少;光是不用再自己處理 findViewById 就省下許多瑣碎工夫。
不過,也不能說所有場景都適合直接換掉舊有 XML,有時候一些現成工具或舊專案依賴傳統方法,還是會讓人猶豫。但整體上,現在已經有將近一半的新專案傾向直接選擇 Compose,就是希望介面和互動可以快速試作與修改。即使如此,也有人仍然懷念過去 XML 那種分離清楚的結構。不管怎樣,看來未來幾年內兩種方式可能還會並存,只是聲明式這條路子漸漸成主流,大致上就是這樣吧。
大概從某個時間點開始,有人注意到 Compose 用聲明式寫法,把元件組合方式弄得有點類似拼積木,減少了重複處理畫面狀態的機會。還聽說如果畫面結構一變動,以前在 XML 那套需要重新安排層級、ID 什麼的,用 Compose 好像彈性就大很多。而且狀態管理這件事,在新的做法下被包裝得簡單不少;光是不用再自己處理 findViewById 就省下許多瑣碎工夫。
不過,也不能說所有場景都適合直接換掉舊有 XML,有時候一些現成工具或舊專案依賴傳統方法,還是會讓人猶豫。但整體上,現在已經有將近一半的新專案傾向直接選擇 Compose,就是希望介面和互動可以快速試作與修改。即使如此,也有人仍然懷念過去 XML 那種分離清楚的結構。不管怎樣,看來未來幾年內兩種方式可能還會並存,只是聲明式這條路子漸漸成主流,大致上就是這樣吧。
LocalComposition 是什麼?不用傳參數也能共享資料的妙招
有時候大家講到這種東西,第一個想到的就是那些冗長又密密麻麻的設定檔,好像不用XML之後,程式碼一下子少了很多——大概讓人覺得乾淨不少。其實,這樣一來要找東西好像也沒那麼困難。再者,有時在畫面更新上,有些朋友觀察到Composable那套機制,只會動到變動的地方,看起來效能或多或少好一些。有人說它處理UI狀態也挺方便,不太需要一直去翻找畫面元件的位置,省下不少瑣碎步驟。
還有一點,那些可組合的小元件,在設計上倒是蠻像一般函式,用起來彈性不小,所以偶爾改點什麼,也不一定要重頭寫過——結構上似乎比較清楚。有的人可能會覺得整體上維護比傳統那種方式輕鬆一點。不過,每個人的習慣和需求都差異滿大,這類優勢到底適合哪些場合,也許得根據實際情境多試幾回才知道。
還有一點,那些可組合的小元件,在設計上倒是蠻像一般函式,用起來彈性不小,所以偶爾改點什麼,也不一定要重頭寫過——結構上似乎比較清楚。有的人可能會覺得整體上維護比傳統那種方式輕鬆一點。不過,每個人的習慣和需求都差異滿大,這類優勢到底適合哪些場合,也許得根據實際情境多試幾回才知道。

為什麼大家都說 Compose 比 XML 好?五大優勢一次看懂
要說在 Jetpack Compose 裡,有沒有那種像 RecyclerView 下 DiffUtil 這種東西,其實有點難直接對應。畢竟架構都換了,很多以前的寫法好像就不再適用,或變得沒那麼必要。有開發者提到,用 Compose 寫列表時,資料更新的方式跟傳統 Android 差滿多。以前大家熟悉的是 DiffUtil 幫忙比對舊新清單,只去動那些真的有差異的項目,大概可以省下不少效能。但現在 Compose 的思想有點轉彎,它本身會觀察資料 State 的變動,自動幫你做些 UI 更新。
實際操作上,如果你的 list 是用 State 或 ViewModel 管理著,每次內容改變後,Compose 就大致會自動判斷哪些要重繪。不過這邊還是有人擔心效率問題,畢竟如果資料量拉高到七十幾個以上、甚至破百,沒好好管理還是可能卡頓。於是,有些人討論是不是要自己手動加 key(像 LazyColumn item 裡頭指定 key),這樣一來 Compose 比較容易追蹤每個元素,不至於亂掉。不過講回來,如果場景單純、數據量不大,好像也沒必須特別去模仿 DiffUtil 那套。
坊間偶爾聽說有人結合 immutable list 再配合 key 或 snapshot state list 之類的新作法,也有些人試著把舊的思維搬過來,但實際效果怎樣,目前看起來似乎要視專案規模和需求決定。有些場合就算全重組畫面也感覺不到什麼 lag。不排除未來 Jetpack 官方再推出更明確的優化方案,所以如果你剛接觸 Compose,在這方面倒也不用太糾結傳統 DiffUtil 做法。有空可以多看看社群分享的新觀點,大概會發現作法其實已經慢慢轉型了。
實際操作上,如果你的 list 是用 State 或 ViewModel 管理著,每次內容改變後,Compose 就大致會自動判斷哪些要重繪。不過這邊還是有人擔心效率問題,畢竟如果資料量拉高到七十幾個以上、甚至破百,沒好好管理還是可能卡頓。於是,有些人討論是不是要自己手動加 key(像 LazyColumn item 裡頭指定 key),這樣一來 Compose 比較容易追蹤每個元素,不至於亂掉。不過講回來,如果場景單純、數據量不大,好像也沒必須特別去模仿 DiffUtil 那套。
坊間偶爾聽說有人結合 immutable list 再配合 key 或 snapshot state list 之類的新作法,也有些人試著把舊的思維搬過來,但實際效果怎樣,目前看起來似乎要視專案規模和需求決定。有些場合就算全重組畫面也感覺不到什麼 lag。不排除未來 Jetpack 官方再推出更明確的優化方案,所以如果你剛接觸 Compose,在這方面倒也不用太糾結傳統 DiffUtil 做法。有空可以多看看社群分享的新觀點,大概會發現作法其實已經慢慢轉型了。
告別 RecyclerView!在 Compose 時代該怎麼處理列表顯示
在 Jetpack Compose 這套東西裡,像 DiffUtil 這種傳統的做法基本上不太用得上。其實也有人說過,LazyColumn 處理清單更新的效率還算可以,只要你有把狀態設計得妥當就好。有些人會搭配 remember 或 snapshotFlow、LazyListState 那幾個東西來看變化,這樣一來,就算資料內容改了,也不用額外處理複雜比對。
比如說,有時候會看到某些寫法,大致像是這樣:
這邊 LaunchedEffect 主要就是檢查列表有沒有變動,有變再去更新。其實只要資料不是大規模暴力更換,效能通常都不會出現明顯問題。
然後,如果有人想找其他相關面試題,好像前面已經整理成五個部分了。要回頭看的話,可以翻一下之前那些連結:第一部分、第二部分、第三和第四部還有第五部,全都列著。如果覺得這些資訊稍微有點用,不妨按個讚或分享出去也行啦——下一輪應該還會再聊更多問題。祝各位寫程式順利吧!
比如說,有時候會看到某些寫法,大致像是這樣:
@Composable
fun ItemList(newItems: List<String>) {
var items by remember { mutableStateOf(newItems) }
LaunchedEffect(newItems) {
if (items != newItems) { // 有點像模仿 DiffUtil 的概念
items = newItems
}
}
LazyColumn {
items(items) { item ->
Text(text = item, modifier = Modifier.padding(8.dp))
}
}
}
這邊 LaunchedEffect 主要就是檢查列表有沒有變動,有變再去更新。其實只要資料不是大規模暴力更換,效能通常都不會出現明顯問題。
然後,如果有人想找其他相關面試題,好像前面已經整理成五個部分了。要回頭看的話,可以翻一下之前那些連結:第一部分、第二部分、第三和第四部還有第五部,全都列著。如果覺得這些資訊稍微有點用,不妨按個讚或分享出去也行啦——下一輪應該還會再聊更多問題。祝各位寫程式順利吧!