如何从 android kotlin 协程获取结果到 UI 线程
How get result to UI Thread from an android kotlin coroutines
我不明白 kotlin 协程是如何工作的。
我需要在异步线程上做很长时间的工作,并在 Android 应用程序的 UI 线程上获得结果。
有人可以给我一些例子吗?
例如
private fun getCountries(){
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
将午餐 model.getAllCountries() 异步但最后我如何才能将结果发送到 UI 线程?
根据 documentation for viewModelScope
:
This scope is bound to Dispatchers.Main.immediate
其中 Dispatchers.Main
是 Kotlin 的说法 'the main thread'。这意味着,默认情况下,launch
块中的所有代码都会在主线程上阻塞 运行。你的 getAllCountries()
,如果它想 运行 在不同的线程上,会想使用 withContext(Disptachers.IO)
移动到 IO 协程调度程序,例如。
因此在这种情况下,您的方法的结果已经在主线程上,您不需要做任何其他事情。
嗯!添加到@ianhanniballake 的回答,
在你的函数中,
private fun getCountries(){
// 1
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
- 您已经从 viewModel 范围启动了
suspend
函数,默认上下文是主线程。
现在 suspend fun getAllCountries
将在其上工作的线程将在 getAllCountries
函数的定义中指定。
所以可以这样写
suspend fun getAllCountries(): Countries {
// 2
return withContext(Disptachers.IO) {
service.getCountries()
}
}
- 我们使用
withContext
指定一个新线程来调用服务器,在 withContext
块的 return 之后,我们回到主线程。
I need to do a long work on an asynchronous thread
实际上,不存在异步线程这样的东西。您的网络操作是同步还是异步取决于您正在使用的网络 API 的实施。
如果您有一个阻塞的网络操作,即使您应用协同程序,它也会保持阻塞状态。该用例的协同程序的价值仅限于使将结果传输回 UI 线程变得更容易一些。
您可以通过使用 UI 调度程序(默认)启动协程然后切换到线程池来执行阻塞操作而不阻塞 UI 线程来实现此目的:
viewModelScope.launch {
countriesList.value = withContext(Dispatchers.IO) {
model.getAllCountries()
}
}
请注意,IO
调度程序下的线程池中的线程仍将被阻塞,因此就系统资源的使用而言,这没有什么不同。阻塞的本机线程将与并发网络调用一样多。
另一种解决方案是 post 在 ViewModel class 内的 MutableLiveData
中得到你的结果,并在你的视图中观察 LiveData。
你的 ViewModel class:
class CountriesViewModel : ViewModel() {
private val parentJob = Job()
val coroutineContext: CoroutineContext
get() = parentJob + Dispatchers.Default
val viewModelScope = CoroutineScope(coroutineContext)
val countries: MutableLiveData<ArrayList<Country>> = MutableLiveData()
val model = MyModel()
fun getCountries(){
viewModelScope.launch {
val countriesList = model.getAllCountries()
countries.postValue(countries)
}
}
}
您的视图class(例如片段)
class CountriesFragment : Fragment(){
private lateinit var countriesVM : CountriesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
countriesVM = ViewModelProviders.of(this).get(CountriesViewModel::class.java)
// calling api in your view model here
countriesVM.getCountries()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// observer is notified of the changes on countries livedata
countriesVM.countries.observe(this, Observer { countries ->
// Update ui here
updateUI(countries)
})
}
}
我不明白 kotlin 协程是如何工作的。 我需要在异步线程上做很长时间的工作,并在 Android 应用程序的 UI 线程上获得结果。 有人可以给我一些例子吗? 例如
private fun getCountries(){
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
将午餐 model.getAllCountries() 异步但最后我如何才能将结果发送到 UI 线程?
根据 documentation for viewModelScope
:
This scope is bound to Dispatchers.Main.immediate
其中 Dispatchers.Main
是 Kotlin 的说法 'the main thread'。这意味着,默认情况下,launch
块中的所有代码都会在主线程上阻塞 运行。你的 getAllCountries()
,如果它想 运行 在不同的线程上,会想使用 withContext(Disptachers.IO)
移动到 IO 协程调度程序,例如。
因此在这种情况下,您的方法的结果已经在主线程上,您不需要做任何其他事情。
嗯!添加到@ianhanniballake 的回答,
在你的函数中,
private fun getCountries(){
// 1
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
- 您已经从 viewModel 范围启动了
suspend
函数,默认上下文是主线程。
现在 suspend fun getAllCountries
将在其上工作的线程将在 getAllCountries
函数的定义中指定。
所以可以这样写
suspend fun getAllCountries(): Countries {
// 2
return withContext(Disptachers.IO) {
service.getCountries()
}
}
- 我们使用
withContext
指定一个新线程来调用服务器,在withContext
块的 return 之后,我们回到主线程。
I need to do a long work on an asynchronous thread
实际上,不存在异步线程这样的东西。您的网络操作是同步还是异步取决于您正在使用的网络 API 的实施。
如果您有一个阻塞的网络操作,即使您应用协同程序,它也会保持阻塞状态。该用例的协同程序的价值仅限于使将结果传输回 UI 线程变得更容易一些。
您可以通过使用 UI 调度程序(默认)启动协程然后切换到线程池来执行阻塞操作而不阻塞 UI 线程来实现此目的:
viewModelScope.launch {
countriesList.value = withContext(Dispatchers.IO) {
model.getAllCountries()
}
}
请注意,IO
调度程序下的线程池中的线程仍将被阻塞,因此就系统资源的使用而言,这没有什么不同。阻塞的本机线程将与并发网络调用一样多。
另一种解决方案是 post 在 ViewModel class 内的 MutableLiveData
中得到你的结果,并在你的视图中观察 LiveData。
你的 ViewModel class:
class CountriesViewModel : ViewModel() {
private val parentJob = Job()
val coroutineContext: CoroutineContext
get() = parentJob + Dispatchers.Default
val viewModelScope = CoroutineScope(coroutineContext)
val countries: MutableLiveData<ArrayList<Country>> = MutableLiveData()
val model = MyModel()
fun getCountries(){
viewModelScope.launch {
val countriesList = model.getAllCountries()
countries.postValue(countries)
}
}
}
您的视图class(例如片段)
class CountriesFragment : Fragment(){
private lateinit var countriesVM : CountriesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
countriesVM = ViewModelProviders.of(this).get(CountriesViewModel::class.java)
// calling api in your view model here
countriesVM.getCountries()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// observer is notified of the changes on countries livedata
countriesVM.countries.observe(this, Observer { countries ->
// Update ui here
updateUI(countries)
})
}
}