rememberCoroutineScope

Kimoji:以 Jetpack Compose 實作一款「心情日記」應用 [28]

John Lu
6 min readOct 1, 2022

今天的文章中,我們要來實作彈出 ModalBottomSheet 的功能。目前,如果嘗試點擊日記上的選單,不會觸發任何動作。

此系列文章是以我的業餘專案: Kimoji 為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
📥 立馬下載

KimojiApp.kt 檔案中的 DiaryScreen composable 裡,在 onMoreClicked callback 中需要開啟 ModalBottomSheet

我們在 KimojiApp 中有一個包含 ModalBottomSheetStateKimojiAppStateModalBottomSheetState 有提供一些函式可以讓我們透過程式開啟和關閉 ModalBottomSheet。不過,如果我們嘗試在 onMoreClicked callback 中寫入 appState.modalBottomSheetState.show(),就會收到錯誤訊息!這是因為 show() 是一個 suspend function。我們又再次回到 coroutines 的世界了。

某些 Compose API 可以讓我們安全地從 UI layer 呼叫 coroutines (例如在昨天的文章中介紹的 LaunchEffect),而某些 Compose API 屬於 suspend function (例如今天的文章要實作的開啟 ModalBottomSheet 的 API)。Suspend function 除了能執行非同步程式碼外,還有助於表示隨著時間演變的概念。開啟 ModalBottomSheet 需要時間和動畫,因此很適合透過 suspend function 完全體現出來。這是因為 suspend function 可以在被呼叫的位置暫停執行 coroutine,直到函式完成並恢復執行為止。

我們必須在 coroutine 裡面呼叫 appState.modalBottomSheetState.show()。可以怎麼做呢?我們來看一下 onMoreClicked 這個簡單的 callback function:

  • 因為 onMoreClicked 並未在 coroutine context 中執行,所以我們不能在它裡面呼叫 suspend functions。
  • 我們沒辦法像之前一樣使用 LaunchedEffect,因為 onMoreClicked 不在 Composition 中,所以無法在它裡面呼叫 composables。

我們希望能夠 launch coroutine,但該使用什麼 scope 呢?在理想情況下,我們希望 CoroutineScope 能夠 follow call-site 的生命週期。方法就是使用 rememberCoroutineScope API。離開 Composition 後,scope 就會自動 cancel。有了這個 scope,即使不在 Composition 中 (例如在 onMoreClicked callback 中),也能啟動 coroutines。

如果我們把 app 跑起來,只要點擊日記上的選單圖示就會開啟 ModalBottomSheet

LaunchedEffect 和 rememberCoroutineScope

由於一般的 callback 在 Composition 以外,我們必須在 callback 中建立 CoroutineScope 才能呼叫 suspend functions,因此在這種情況下無法使用 LaunchedEffect

回想一下昨天我們使用 LaunchedEffect 來顯示 landing screen 的 code,我們可以在不使用 LaunchedEffect 的情況下,使用 rememberCoroutineScope 並呼叫 scope.launch { delay(); onTimeout(); } 嗎?

我們本來可以這樣做,也似乎可行,但這樣並不正確。如仝我們前幾天在 Compose Recomposition 文章中所述,Composable function 可能會很頻繁地被執行。當呼叫 composable 並進入 Composition 時,LaunchedEffect 保證會執行 side-effect。如果在 LandingScreen 的 body 中使用 rememberCoroutineScopescope.launch,則每次 Compose 呼叫 LandingScreen 時,不論該呼叫是否為 initial Composition,coroutine 都會被執行。因此,我們不僅會耗費資源,而且基本上會讓執行這個 side-effect 的情況不受控。

此系列文章是以我的業餘專案: Kimoji 為範例

Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
📥 立馬下載

--

--

John Lu
John Lu

Written by John Lu

AI Engineer. Deeply motivated by challenges and tends to be excited by breaking conventional ways of thinking and doing. He builds fun and creative apps.

No responses yet