在进行网络调用时使用协程更新 UI
Use coroutines to update UI while making network call
我试图在使用协程进行网络调用时显示微调器。 UI 似乎不显示 LOADING_ITEMS 状态(旋转器),直到 itemsFromRepo 调用 returns,然后旋转器显示一瞬间,然后显示项目。我的印象是,因为它在协程中,状态将设置为 LOADING_ITEMS,项目将被清除,网络调用将在微调器显示在 [=19] 上时在后台进行=].然后当网络调用完成时,协程将继续 运行 并设置项目然后状态。
这是协程的正确使用方式吗?还有范围,我认为这是我几个月前玩过的实验性协同程序的新功能。
// 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)
}
}
}
关于你的问题:
Is this the correct way of using Coroutines?
是的,这是正确的方法。如果您在 suspend
函数中有网络调用(在您的情况下),那么此函数将暂停协程执行,直到您调用 continuation.resume()
或其他相关方法来恢复协程。并且挂起协程不会阻塞main
线程。
我试图在使用协程进行网络调用时显示微调器。 UI 似乎不显示 LOADING_ITEMS 状态(旋转器),直到 itemsFromRepo 调用 returns,然后旋转器显示一瞬间,然后显示项目。我的印象是,因为它在协程中,状态将设置为 LOADING_ITEMS,项目将被清除,网络调用将在微调器显示在 [=19] 上时在后台进行=].然后当网络调用完成时,协程将继续 运行 并设置项目然后状态。
这是协程的正确使用方式吗?还有范围,我认为这是我几个月前玩过的实验性协同程序的新功能。
// 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)
}
}
}
关于你的问题:
Is this the correct way of using Coroutines?
是的,这是正确的方法。如果您在 suspend
函数中有网络调用(在您的情况下),那么此函数将暂停协程执行,直到您调用 continuation.resume()
或其他相关方法来恢复协程。并且挂起协程不会阻塞main
线程。