我不了解Kotlin协程的工作方式。 我需要在异步线程上进行长时间的工作,并在Android应用程序的UI线程上获得结果。 有人可以给我一些例子吗? 例如
private fun getCountries(){
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
午餐model.getAllCountries()是否会异步,但最终如何将结果获取到UI线程?
答案 0 :(得分:3)
好吧!除了@ianhanniballake的答案,
在您的职能中,
private fun getCountries(){
// 1
viewModelScope.launch {
val a = model.getAllCountries()
countriesList.value = a
}
}
suspend
函数,默认上下文是主线程。现在将在suspend fun getAllCountries
函数的定义中指定将运行getAllCountries
的线程。
因此它可以写为
suspend fun getAllCountries(): Countries {
// 2
return withContext(Disptachers.IO) {
service.getCountries()
}
}
withContext
来调用服务器,并且从withContext
块返回之后,我们又回到了主线程上。答案 1 :(得分:2)
按照documentation for viewModelScope
:
public void OnDominantSpeakerChanged(Room room, RemoteParticipant remoteParticipant) {
if (remoteParticipant!=null) {
if (remoteParticipant.RemoteVideoTracks.Count > 0) {
RemoteVideoTrackPublication remoteVideoTrackPublication = remoteParticipant.RemoteVideoTracks[0];
remoteParticipantIdentity = remoteParticipant.Identity;
AddRemoteParticipantVideo(remoteVideoTrackPublication.RemoteVideoTrack);
}
}
}
是Kotlin说“主线程”的方式。这意味着默认情况下,Dispatchers.Main
块中的所有代码都在主线程上运行。例如,您的launch
要在另一个线程上运行,则想使用getAllCountries()
移至IO协程分派器。
因此,在这种情况下,您的方法的结果已经在主线程上已经,并且您无需执行其他任何操作。
答案 2 :(得分:0)
我需要在异步线程上做长时间的工作
实际上没有异步线程之类的东西。您的网络操作是同步还是异步取决于您所使用的网络API的实现。
如果您有阻止网络操作,则即使应用协程,它也将保持阻止状态。在该用例中,协程的价值仅限于使将结果传输回UI线程更加容易。
您可以通过使用UI调度程序(默认值)启动协程,然后切换到线程池以执行阻塞操作而不阻塞UI线程来实现此目的:
viewModelScope.launch {
countriesList.value = withContext(Dispatchers.IO) {
model.getAllCountries()
}
}
请注意,IO
调度程序下面的线程池中的线程仍将被阻塞,因此就系统资源的使用而言,这没有什么区别。阻塞的本机线程将与并发网络调用一样多。
答案 3 :(得分:0)
另一种解决方案是将结果发布到ViewModel类内的MutableLiveData
中,并在视图中观察LiveData。
您的 ViewModel 类:
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 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)
})
}
}