iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0

加入 LifecycleScope 管理 Coroutine

經友人 L 建議,可以透過 LifecycleScope 管理 coroutine 的生命週期。因為在此 LifecycleScope 範圍內的 coroutine 都會在 Lifecycle 被銷毀時自動取消。

在 Gradle(Module)內加入 :

androidx.lifecycle:lifecycle-runtime-ktx:2.4.0

CoroutineScope(Dispatchers.Main).launch {} 修改為用 LifecycleScope.launch {} 啟動 coroutine :

// 原始程式碼
CoroutineScope(Dispatchers.Main).launch {

}
// 修改後

lifecycleScope.launch(Dispatchers.Main) {
    try {

        binding.progressbar.visibility = View.VISIBLE
        fetchCoffeeShopData()
    }
    catch (e: CoffeeShopsRefreshError) {

        binding.progressbar.visibility = View.INVISIBLE
        binding.textView.text = "Request failed \nmessage: ${e.message}"
    }
}

修改好啦~執行起來也一切正常!

d12_1.png

實作 Async 執行非同步任務

點擊按鈕後執行 refreshText() 來測試使用 async 啟動執行緒 :

// TODO: test async
binding.button.setOnClickListener {

    refreshText()
}

運作的流程大概是這樣 :

  1. 在主執行緒中啟動 coroutine
  2. 接著使用 async(Dispatchers.IO) 在 IO 執行緒啟動 coroutine執行非同步任務,這邊透過 delay(1000) 模擬非同步情形並回傳 Deferred<String> ,使用變數 rawText 儲存回傳結果
  3. 呼叫 await() 等待非同步的執行結果,取到後使用變數 deferredResult 儲存非同步結果
  4. 最後直接刷新畫面,應顯示 “async result”
private fun refreshText() {

    lifecycleScope.launch(Dispatchers.Main) {

        binding.progressbar.visibility = View.VISIBLE

        // 非同步執行取得 "async result"
        val rawText: Deferred<String> = lifecycleScope.async(Dispatchers.IO) {
            delay(1000)
            "async result"
        }

        // 等待非同步執行結果
        val deferredResult = rawText.await()

        // 更新
        binding.textView.text = deferredResult
        binding.progressbar.visibility = View.GONE
    }
}

d12_2.png

我們成功拉~~~

看來方向沒有錯,接著在試著將取得非同步文字那段程式碼寫成方法提出去。

先看一眼 Kotlin 的方法要怎麼寫 :

d12_3.png

要回傳的型別寫在冒號後面,看習慣 Java 的我只覺得眼睛業障重…

來改寫吧,因為未來是用呼叫 API 的方式來取得非同步結果,先從簡單的開始練習 :

// 待修改的程式碼
val rawText: Deferred<String> = lifecycleScope.async(Dispatchers.IO) {
            delay(1000)
            "async result"
}

加入 getAsyncText() :

/**
 * 非同步執行取得 "async result"
 */
private suspend fun getAsyncText(): Deferred<String> {

    return lifecycleScope.async(Dispatchers.IO) {
        delay(1000)
        "async result"
    }
}

refreshText() :

// 修改後

private fun refreshText() {

    lifecycleScope.launch(Dispatchers.Main) {

        binding.progressbar.visibility = View.VISIBLE

        // 等待非同步執行結果
        val deferredResult = getAsyncText().await()

        // 更新
        binding.textView.text = deferredResult
        binding.progressbar.visibility = View.GONE
    }
}

再次成功了~~~

d12_4.png

每天都寫個一小點,慢慢地就會完成專案了吧~~~

目前進度有點落後呀

今日推推

Yes


上一篇
Day11 二戰 Coroutine ! 使用 OKHttp 串接全台咖啡廳資料的 API-5
下一篇
Day13 使用 Async 啟動 Coroutine 取得網路請求 (下)
系列文
喝咖啡要30天?一起用 Kotlin 打造尋找好喝咖啡的 App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言