You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中如何等待Retrofit调用完成后执行后续函数?

问题

在Jetpack Compose应用中使用Retrofit从API获取数据时,遇到异步顺序问题:调用getLocation函数后会立刻执行viewModel.updateFlightSearch,但此时viewModel.location.value仍为null——因为Retrofit的异步请求还未完成。需要等待Retrofit请求完成、location变量更新后,再执行updateFlightSearch。

现有代码如下:

获取位置的函数

fun getLocation(name: String) =
        viewModelScope.launch(Dispatchers.IO) {
            _loading.value = true
            val response = repository.getLocation(name)

            when (response) {
                is Resource.Success -> {
                    _location.value = response.data!!.first()
                    _loading.value = false
                }
                is Resource.Loading -> {
                    _loading.value = true
                }
                is Resource.Error -> {
                    _error.value = response.message.toString()
                    Log.d("ErrorLocation", _error.value)
                    _loading.value = false
                }
            }
        }

更新航班搜索数据的函数

fun updateFlightSearch(
        cityDep: String = "", cityArr: String = "", date: String = "", pass: Int = 0
    ) {
        if (cityDep != "")
            _flightSearch.value.locationDeparture = cityDep
        if (cityArr != "")
            _flightSearch.value.locationArrival = cityArr
        if (date != "")
            _flightSearch.value.departureTime = date
        if (pass != 0)
            _flightSearch.value.passengers = pass
    }

点击按钮后的调用逻辑

MyDialog(
                openDialog = viewModel.isDialogOpen,
                param = viewModel.selectedButtonName.value,
                
                ) { city ->
                when (viewModel.selectedButtonIndex.value) {
                    0 -> {
                        viewModel.getLocation(city)
                        viewModel.updateFlightSearch(viewModel.location.value.cityCode.toString())

                    }
解决方案

方法一:将getLocation改为挂起函数,顺序执行

把getLocation改成挂起函数,这样在协程中调用时会等待请求完成,再执行后续代码,从根源上解决异步顺序问题。

修改getLocation:

suspend fun getLocation(name: String) {
    _loading.value = true
    val response = repository.getLocation(name)

    when (response) {
        is Resource.Success -> {
            _location.value = response.data!!.first()
            _loading.value = false
        }
        is Resource.Loading -> {
            _loading.value = true
        }
        is Resource.Error -> {
            _error.value = response.message.toString()
            Log.d("ErrorLocation", _error.value)
            _loading.value = false
        }
    }
}

在点击回调中启动协程,顺序调用两个函数:

MyDialog(
    openDialog = viewModel.isDialogOpen,
    param = viewModel.selectedButtonName.value,
    
    ) { city ->
    when (viewModel.selectedButtonIndex.value) {
        0 -> {
            viewModel.viewModelScope.launch {
                viewModel.getLocation(city)
                // 用let处理location可能为null的情况,避免空指针
                viewModel.location.value?.let { location ->
                    viewModel.updateFlightSearch(cityDep = location.cityCode.toString())
                }
            }
        }
    }
}

方法二:在getLocation成功分支直接调用updateFlightSearch

如果updateFlightSearch的调用逻辑和getLocation的成功结果强绑定,可以直接在请求成功后触发更新,同时通过参数标记是更新出发地还是目的地:

修改getLocation并添加更新类型枚举:

// 定义枚举标记要更新的位置类型
enum class UpdateType {
    DEPARTURE, ARRIVAL
}

fun getLocation(name: String, updateType: UpdateType) =
        viewModelScope.launch(Dispatchers.IO) {
            _loading.value = true
            val response = repository.getLocation(name)

            when (response) {
                is Resource.Success -> {
                    val location = response.data!!.first()
                    _location.value = location
                    _loading.value = false
                    // 请求成功后直接更新航班搜索数据
                    when(updateType) {
                        UpdateType.DEPARTURE -> updateFlightSearch(cityDep = location.cityCode.toString())
                        UpdateType.ARRIVAL -> updateFlightSearch(cityArr = location.cityCode.toString())
                    }
                }
                is Resource.Loading -> {
                    _loading.value = true
                }
                is Resource.Error -> {
                    _error.value = response.message.toString()
                    Log.d("ErrorLocation", _error.value)
                    _loading.value = false
                }
            }
        }

点击回调中调用方式改为:

MyDialog(
    openDialog = viewModel.isDialogOpen,
    param = viewModel.selectedButtonName.value,
    
    ) { city ->
    when (viewModel.selectedButtonIndex.value) {
        0 -> {
            viewModel.getLocation(city, UpdateType.DEPARTURE)
        }
    }
}

方法三:监听location状态变化自动触发更新

如果需要响应location的每次变化来同步航班搜索数据,可以在Compose层用LaunchedEffect监听location的变化:

// 在Compose界面中添加
LaunchedEffect(viewModel.location.value) {
    viewModel.location.value?.let { location ->
        // 仅在选中出发地按钮时更新
        if(viewModel.selectedButtonIndex.value == 0) {
            viewModel.updateFlightSearch(cityDep = location.cityCode.toString())
        }
    }
}

这种方式适合需要实时响应location变化的场景,但要注意添加判断条件,避免不必要的更新触发。

内容的提问来源于stack exchange,提问作者deja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:09:18