簡體   English   中英

使用協同程序在進行網絡呼叫時更新UI

[英]Use coroutines to update UI while making network call

我正在嘗試使用協同程序進行網絡調用時顯示一個微調器。 UI似乎沒有顯示LOADING_ITEMS狀態(一個微調器),直到itemsFromRepo調用返回,然后微調器顯示一瞬間,然后顯示項目。 我的印象是,在協程中,狀態將被設置為LOADING_ITEMS,項目將被清除,當微調器在UI上顯示時,網絡調用將在后台進行。 然后,當網絡調用完成后,協程將繼續運行並設置項目然后狀態。

這是使用Coroutines的正確方法嗎? 和范圍,我認為這是我幾個月前玩過的實驗協同程序的新功能。

// ViewModel.kt
enum class State { LOADING_ITEMS, SELECTING_ITEM } 

var state = ObservableField<State>()   
var items = ObservableField<List<String>>()    

private fun loadItems() {
    state.set(State.LOADING_ITEMS)
    items.set(emptyList())
    GlobalScope.launch(Dispatchers.Main) {
        val itemsFromRepo = apiRepo.getItems() // a network call
        items.set(itemsFromRepo)
        state.set(State.SELECTING_ITEM)
    }
}


// Repo.kt
suspend fun getItems() = suspendCoroutine<List<String>> { cont ->
    FirebaseDatabase.getInstance().getReference("Items")
            .addListenerForSingleValueEvent(
            object : ValueEventListener {
                override fun onCancelled(error: DatabaseError?) {
                    cont.resume(listOf(error?.message ?: "Unknown error"))
                }

                override fun onDataChange(snap: DataSnapshot?) {
                    cont.resume(snap?.children?.map { it.key } ?: emptyList())
                }
            })
}

最佳實踐是使用本地范圍來處理協同程序:

class ViewModel : CoroutineScope {
    private var job: Job = Job()

    // To use Dispatchers.Main (CoroutineDispatcher - runs and schedules coroutines) in Android add
    // implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    enum class State { LOADING_ITEMS, SELECTING_ITEM } 

    var state = ObservableField<State>()   
    var items = ObservableField<List<String>>()


    fun detachView() {
        job.cancel()
    }

    private fun loadItems() {
        state.set(State.LOADING_ITEMS)
        items.set(emptyList())
        launch {
            val itemsFromRepo = apiRepo.getItems()
            items.set(itemsFromRepo)
            state.set(State.SELECTING_ITEM)
        }
    }
}

關於你的問題:

這是使用Coroutines的正確方法嗎?

是的,這是正確的方法。 如果你在suspend函數(在你的情況下)中有網絡調用,那么這個函數將暫停協程執行,直到你調用continuation.resume()或其他相關方法來恢復協程。 並且掛起協程不會阻止main線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM