如何等待 retrofit.getData() 完成 Kotlin 协程
How to wait for retrofit.getData() complete Kotlin Coroutines
我正在从 API 获取数据,我需要等到作业完成。因为 MutableLiveData。
当它工作时 response.isSusccesful=false 然后它变成 true。我如何等到 retrofit.getData() 完成。我试过 runblocking 但它不是合适的方法。我尝试了 async{} 和 await() 但我也没成功。
fun loadData():ArrayList<CryptoData> {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
job = viewModelScope.launch {
withContext(Dispatchers.IO){
val response = retrofit.getData()
withContext(Dispatchers.Main){
if (response.isSuccessful){
response.body()?.let {
cryptoDatas = ArrayList(it)
currency.value = cryptoDatas
progressBarStatus.value = false
println(response.isSuccessful)
}
}
else{
println(response.isSuccessful)
}
}
}
}
return cryptoDatas
}
如果你的 getData()
是一个 suspend
函数你应该没问题,因为默认情况下协同程序中的代码是顺序的,这意味着 val response = retrofit.getData()
下面的任何东西都不能 运行 直到getData()
returns.
如果它不只是使它成为一个 suspend
函数,因为 Retrofit 本身就支持它。
@GET("...")
suspend fun getData(): Response<...>
关于这个问题,你可以打电话给job.join()
等待工作完成,但对你来说这根本帮不了你。 join()
是一个挂起函数,因此必须从另一个 suspend
函数或另一个协程调用它。
首先,您应该确保 getData()
被定义为一个挂起函数,这样您就不必欺骗那些 withContext
包装器。调用正确编写的挂起函数时不需要它们,因为正确的挂起函数不会阻塞,如果需要特定的挂起函数,它们会在内部委托给适当的调度程序。
那么你有两个选择。
- 不是从函数返回某些东西,而是将结果发布到 LiveData(或 SharedFlow/StateFlow)。外部 class 可以调用此函数并观察 LiveData 以处理结果。
private val _cryptoData = MutableLiveData<ArrayList<CryptoData>>()
val cryptoData: LiveData<ArrayList<CryptoData>> = _cryptoData
fun loadData() {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
viewModelScope.launch {
val response = retrofit.getData()
if (response.isSuccessful){
response.body()?.let {
cryptoData.value = ArrayList(it)
currency.value = it
progressBarStatus.value = false
println(response.isSuccessful)
}
else {
println(response.isSuccessful)
}
}
}
- 使
loadData()
成为暂停功能。你的外部 class 可以使用协程调用它,然后按顺序对结果进行处理。
suspend fun loadData(): List<CryptoData>? {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
val response = retrofit.getData()
return if (response.isSuccessful){
response.body()?.let {
currency.value = it
progressBarStatus.value = false
println(response.isSuccessful)
ArrayList(it)
}
} else {
println(response.isSuccessful)
null
}
}
但我从字里行间看出,这是您每次显示此片段或 Activity 时加载的数据。所以你应该使用选项 1,除非你将这个函数设为私有并从 init
块中调用它。这样,外部class只需要观察LiveData,如果用户旋转设备,就不会每次都重新开始请求,延迟数据加载完成。
我正在从 API 获取数据,我需要等到作业完成。因为 MutableLiveData。 当它工作时 response.isSusccesful=false 然后它变成 true。我如何等到 retrofit.getData() 完成。我试过 runblocking 但它不是合适的方法。我尝试了 async{} 和 await() 但我也没成功。
fun loadData():ArrayList<CryptoData> {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
job = viewModelScope.launch {
withContext(Dispatchers.IO){
val response = retrofit.getData()
withContext(Dispatchers.Main){
if (response.isSuccessful){
response.body()?.let {
cryptoDatas = ArrayList(it)
currency.value = cryptoDatas
progressBarStatus.value = false
println(response.isSuccessful)
}
}
else{
println(response.isSuccessful)
}
}
}
}
return cryptoDatas
}
如果你的 getData()
是一个 suspend
函数你应该没问题,因为默认情况下协同程序中的代码是顺序的,这意味着 val response = retrofit.getData()
下面的任何东西都不能 运行 直到getData()
returns.
如果它不只是使它成为一个 suspend
函数,因为 Retrofit 本身就支持它。
@GET("...")
suspend fun getData(): Response<...>
关于这个问题,你可以打电话给job.join()
等待工作完成,但对你来说这根本帮不了你。 join()
是一个挂起函数,因此必须从另一个 suspend
函数或另一个协程调用它。
首先,您应该确保 getData()
被定义为一个挂起函数,这样您就不必欺骗那些 withContext
包装器。调用正确编写的挂起函数时不需要它们,因为正确的挂起函数不会阻塞,如果需要特定的挂起函数,它们会在内部委托给适当的调度程序。
那么你有两个选择。
- 不是从函数返回某些东西,而是将结果发布到 LiveData(或 SharedFlow/StateFlow)。外部 class 可以调用此函数并观察 LiveData 以处理结果。
private val _cryptoData = MutableLiveData<ArrayList<CryptoData>>()
val cryptoData: LiveData<ArrayList<CryptoData>> = _cryptoData
fun loadData() {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
viewModelScope.launch {
val response = retrofit.getData()
if (response.isSuccessful){
response.body()?.let {
cryptoData.value = ArrayList(it)
currency.value = it
progressBarStatus.value = false
println(response.isSuccessful)
}
else {
println(response.isSuccessful)
}
}
}
- 使
loadData()
成为暂停功能。你的外部 class 可以使用协程调用它,然后按顺序对结果进行处理。
suspend fun loadData(): List<CryptoData>? {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CryptoAPI::class.java)
val response = retrofit.getData()
return if (response.isSuccessful){
response.body()?.let {
currency.value = it
progressBarStatus.value = false
println(response.isSuccessful)
ArrayList(it)
}
} else {
println(response.isSuccessful)
null
}
}
但我从字里行间看出,这是您每次显示此片段或 Activity 时加载的数据。所以你应该使用选项 1,除非你将这个函数设为私有并从 init
块中调用它。这样,外部class只需要观察LiveData,如果用户旋转设备,就不会每次都重新开始请求,延迟数据加载完成。