使用协程在进行网络调用时更新 UI



我正在尝试在使用协程进行网络调用时显示微调器。UI 似乎不显示LOADING_ITEMS状态(微调器),直到 itemsFromRepo 调用返回,然后微调器显示一秒钟,然后显示项目。我的印象是,由于它在协程中,状态将设置为 LOADING_ITEMS,项目将被清除,网络调用将在后台进行,而微调器显示在 UI 上。然后,当网络调用完成后,协程将继续运行并设置项目然后状态。

这是使用协程的正确方法吗?范围,我认为这是我几个月前玩过的实验协程的新内容。

// 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)
        }
    }
}

关于你的问题:

这是使用协程的正确方法吗?

是的,这是正确的方式。如果在 suspend 函数中有网络调用(在本例中),则此函数将暂停协程执行,直到您调用continuation.resume()或其他相关方法来恢复协程。挂起协程不会阻塞main线程。

相关内容

  • 没有找到相关文章

最新更新