作法一:async + await(我要結果,但任務不能停)
這招的核心是「分離執行與等待的生命週期」。Repository 接受一個長壽的 externalScope,用 async 把任務丟進去獨立執行,UI 層則用 await 等待結果。UI 離開,await 取消,但 async 區塊的任務會繼續完成。
Kotlin
// In NewsRepository.kt class NewsRepository( private val newsApi: NewsApiService, // 由外部 DI 框架提供一個 Application-Scope private val externalScope: CoroutineScope ) { private var cachedNews: List<News> = emptyList() private val mutex = Mutex() suspend fun getLatestNews(): List<News> { // 使用 async 將任務發射到外部 Scope,並用 await 等待結果 return externalScope.async { val result = newsApi.fetchLatest() mutex.withLock { cachedNews = result } result }.await() } }
作法二:launch + Flow(射後不理,我只觀察)
說實話,async/await 有點像在門口乾等外送。在多數情況下,一個更優雅、更解耦的作法是「射後不理」。UI 只負責觸發刷新,然後持續觀察一個資料流 (Flow) 的變化。
Kotlin
// In NewsRepository.kt class NewsRepository(...) { private val _newsFlow = MutableStateFlow<List<News>>(emptyList()) val newsFlow: StateFlow<List<News>> = _newsFlow // 刷新方法變成射後不理 fun refreshNews() { externalScope.launch { val result = newsApi.fetchLatest() _newsFlow.value = result // 更新資料流,UI 會自動收到 } } } // In NewsViewModel.kt class NewsViewModel(private val repo: NewsRepository) : ViewModel() { val news = repo.newsFlow // 直接觀察 Flow fun onRefresh() { repo.refreshNews() // 只需觸發,不用等待 } }