LaunchedEffect 和 rememberUpdatedState
我們想要在 Kimoji App 中新增一個 landing screen,可以用來在背景載入資料。
此系列文章是以我的業餘專案: Kimoji 為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
📥 立馬下載
Landing screen 會占滿整個螢幕,並會在畫面中央顯示 app logo。理想情況下,我們會顯示畫面,並在所有資料載入完畢後通知 caller,讓 caller 知道可以使用 onTimeout
callback 來關閉 landing screen。
如要在 Android 中執行非同步作業,建議使用 Kotlin coroutines。一般情況下,會在 app 啟動時使用 coroutines 在背景中載入內容。而 Jetpack Compose 提供的 API,可讓我們在 UI layer 中安全地使用 coroutines。因為 Kimoji App 目前還沒有串接 server,因此我們會使用 coroutines 的 delay
函式,來模擬在背景中載入內容。
Compose 的 side-effect 是指 app state 在 composable function 的 scope 以外發生改變。例如,在使用者點擊按鈕時開啟新的畫面,或是在 app 沒連上網路時顯示訊息。
Compose 的 side-effect 是指 app state 在 composable function 的 scope 以外發生改變。改變狀態來顯示/隱藏 landing screen 的操作會發生在 onTimeout
的 callback 中。由於在呼叫 onTimeout
前,我們必須使用 coroutines 來載入內容,因此狀態改變必須發生在 coroutine 的 context 中。
如要從 composable 裡安全地呼叫 suspend function,可以使用 LaunchedEffect
API,進而在 Compose 中觸發帶有 coroutine scope 的 side-effect。
當 LaunchedEffect
進入 Composition 時,就會 launch 一個 coroutine 來執行 block
參數裡的程式碼。如果 LaunchedEffect
離開 Composition,coroutine 就會取消。
雖然接下來的程式碼不正確,但我們可以看看如何使用這個 API,並討論下列程式碼錯誤的原因。我們之後會示範正確的寫法。
某些 side-effect API (例如 LaunchedEffect
) 會接受任意數量的 key 做為參數,當其中一個 key 變更時會重新啟動 side-effect。發現 bug 在哪了嗎?我們不希望在 onTimeout
改變時重新啟動 side-effect!
如要在這個 composable 的 lifecycle 中只觸發一次 side-effect,要使用常數做為 key,例如 LaunchedEffect(true) { ... }
。不過,我們現在並沒有處理 onTimeout
改變的情況!
如果 onTimeout
在 side-effect 執行到一半時發生改變,side-effect 結束時不一定會呼叫最新的 onTimeout
。我們可以使用 rememberUpdatedState
API 來捕捉並更新到新的值來保證做到這一點:
顯示 landing screen
現在,我們要在 app 開啟時顯示 landing screen。開啟 MainScreen.kt
檔案,然後找到呼叫 KimojiApp
的 composable。
在 MainScreen
composable 中,我們只需新增一個 internal state,即可決定是否要顯示 landing screen:
如果現在把 app 跑起來,畫面上應會顯示 LandingScreen
,然後在 2 秒後消失。
此系列文章是以我的業餘專案: Kimoji 為範例
Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
📥 立馬下載