iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
Mobile Development

Jetpack Compose 從心開始系列 第 16

Jetpack Compose 從心開始 Day16 - Android 中的協同程式

  • 分享至 

  • xImage
  •  

前言

    練習完kotlin 協同程式 語法,那app就來試用看看吧

嫦娥跑跑

嫦娥跑跑 應用程式會模擬兩位參加賽跑的玩家。應用程式 UI 包含「Start」/「Pause」和「Reset」這兩個按鈕,以及兩條顯示玩家進度的進度列。玩家 1 和 2 將以不同速度「賽跑」。賽跑開始時,玩家 2 的跑步速度是玩家 1 的兩倍。

https://ithelp.ithome.com.tw/upload/images/20240926/20121643YBBQvrF2ag.png

使用suspend function暫停函式

suspend fun run() {
    while (currentProgress < maxProgress) {
        delay(progressDelayMillis)
        currentProgress += progressIncrement
    }
}

https://ithelp.ithome.com.tw/upload/images/20240926/20121643iBOcoMCInU.png

使用 LaunchedEffect() 可組合函式

使用 LaunchedEffect() 可組合函式,就能安全地從可組合函式呼叫暫停函式。

var raceInProgress by remember { mutableStateOf(false) }

    if (raceInProgress) {
        LaunchedEffect(playerOne, playerTwo) {
            launch {playerOne.run() }
            launch {playerTwo.run() }
        raceInProgress = false 
        }
    }

結構化並行

改用 coroutineScope

var raceInProgress by remember { mutableStateOf(false) }

   if (raceInProgress) {
       LaunchedEffect(playerOne, playerTwo) {
           coroutineScope {
               launch { playerOne.run() }
               launch { playerTwo.run() }
           }
           raceInProgress = false
       }
   }

https://ithelp.ithome.com.tw/upload/images/20240926/20121643zsY3k0rOZu.png

run() 方法的加入 try-catch 區塊

suspend fun run() {
    try {
        while (currentProgress < maxProgress) {
            delay(progressDelayMillis)
            currentProgress += progressIncrement
        }
    } catch (e: CancellationException) {
        Log.e("RaceParticipant", "$name: ${e.message}")
        throw e // Always re-throw CancellationException.
    }
}

撰寫用來測試協同程式的單元測試

@Test
    fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
        val expectedProgress = 1
        launch { raceParticipant.run() }
        advanceTimeBy(raceParticipant.progressDelayMillis)
        runCurrent()
        assertEquals(expectedProgress, raceParticipant.currentProgress)
    }

    @Test
    fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
        launch { raceParticipant.run() }

        advanceTimeBy(raceParticipant.maxProgress * raceParticipant.progressDelayMillis)
        runCurrent()
        assertEquals(100, raceParticipant.currentProgress)
    }

    @Test
    fun raceParticipant_RacePaused_ProgressUpdated() = runTest {
        val expectedProgress = 5
        val racerJob = launch { raceParticipant.run() }
        advanceTimeBy(expectedProgress * raceParticipant.progressDelayMillis)
        runCurrent()
        racerJob.cancelAndJoin()
        assertEquals(expectedProgress, raceParticipant.currentProgress)
    }

    @Test
    fun raceParticipant_RacePausedAndResumed_ProgressUpdated() = runTest {
        val expectedProgress = 5

        repeat(2) {
            val racerJob = launch { raceParticipant.run() }
            advanceTimeBy(expectedProgress * raceParticipant.progressDelayMillis)
            runCurrent()
            racerJob.cancelAndJoin()
        }

        assertEquals(expectedProgress * 2, raceParticipant.currentProgress)
    }

    @Test(expected = IllegalArgumentException::class)
    fun raceParticipant_ProgressIncrementZero_ExceptionThrown() = runTest {
        RaceParticipant(name = "Progress Test", progressIncrement = 0)
    }

    @Test(expected = IllegalArgumentException::class)
    fun raceParticipant_MaxProgressZero_ExceptionThrown() {
        RaceParticipant(name = "Progress Test", maxProgress = 0)
    }

測式結果

https://ithelp.ithome.com.tw/upload/images/20240926/20121643UZ8NPSRDGV.png


上一篇
Jetpack Compose 從心開始 Day15 - 協同程式
下一篇
Jetpack Compose 從心開始 Day17 -從網際網路取得資料
系列文
Jetpack Compose 從心開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言