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

Android Retrofit API调用无响应无报错问题排查求助

问题排查:Retrofit API调用未触发(ViewModel函数未执行)

核心问题

ViewModel中的fetchingBanner()函数完全未执行,导致Retrofit API调用未触发,根源在于UI层从未向ViewModel发送触发请求的Intent,同时存在Intent设计冗余、状态处理不完善等问题。


具体排查与修复步骤

1. 修复HomeIntent的冗余设计

原LoadBanners Intent携带了不必要的参数(要获取的数据列表),这会造成逻辑混淆,修改为无参数的事件:

sealed class HomeIntent {
    object LoadBanners : HomeIntent() // 仅作为触发加载的信号,无需传参
}

2. 完善ViewModel的逻辑处理

  • 匹配修改后的无参数Intent
  • 添加加载状态通知
  • 安全处理响应体(避免空指针)
  • 补充异常捕获与详细错误信息
@HiltViewModel
class HomeViewModel @Inject constructor(private val repository: HomeRepository) : ViewModel() {
    val intentChannel = Channel<HomeIntent>()
    private val _state = MutableStateFlow<HomeState>(HomeState.Idle)
    val state: StateFlow<HomeState> get() = _state

    init {
        handleIntents()
    }

    private fun handleIntents() = viewModelScope.launch {
        intentChannel.consumeAsFlow().collect { intent ->
            when (intent) {
                HomeIntent.LoadBanners -> fetchingBanner() // 匹配无参数Intent
            }
        }
    }

    private suspend fun fetchingBanner() {
        _state.emit(HomeState.LoadingBanner) // 发送加载中状态,更新UI
        try {
            val response = repository.getBannerList()
            when (response.code()) {
                in 200..202 -> {
                    val bannerList = response.body() ?: mutableListOf()
                    if (bannerList.isEmpty()) {
                        _state.emit(HomeState.Empty)
                    } else {
                        _state.emit(HomeState.BannerListItem(bannerList))
                    }
                }
                in 400..499 -> {
                    _state.emit(HomeState.Error("客户端错误:${response.code()}"))
                }
                in 500..599 -> {
                    _state.emit(HomeState.Error("服务端错误:${response.code()}"))
                }
                else -> {
                    _state.emit(HomeState.Error("未知错误:${response.code()}"))
                }
            }
        } catch (e: Exception) {
            // 捕获网络异常、解析异常等
            _state.emit(HomeState.Error("请求失败:${e.message ?: "未知错误"}"))
        }
    }
}

3. 在Fragment中发送Intent并完善UI逻辑

原Fragment仅观察状态但未发送触发请求的Intent,添加Intent发送逻辑,并完善状态对应的UI更新:

@AndroidEntryPoint
class HomeFragment : Fragment() {
    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    @Inject
    lateinit var bannerAdapter: AdapterBanner

    private val viewModel: HomeViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化RecyclerView
        binding.bannerRecyclerView.apply {
            adapter = bannerAdapter
            layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
        }

        // 发送加载Banner的Intent,触发API调用
        viewModel.viewModelScope.launch {
            viewModel.intentChannel.send(HomeIntent.LoadBanners)
        }

        // 观察ViewModel状态,更新UI
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.state.collect { state ->
                    when (state) {
                        HomeState.Idle -> {}
                        HomeState.LoadingBanner -> {
                            binding.loadingProgress.visibility = View.VISIBLE
                            binding.emptyState.visibility = View.GONE
                        }
                        HomeState.LoadingProfile -> {}
                        is HomeState.BannerListItem -> {
                            binding.loadingProgress.visibility = View.GONE
                            bannerAdapter.submitList(state.banner)
                        }
                        HomeState.Empty -> {
                            binding.loadingProgress.visibility = View.GONE
                            binding.emptyState.visibility = View.VISIBLE
                        }
                        is HomeState.Error -> {
                            binding.loadingProgress.visibility = View.GONE
                            Toast.makeText(requireContext(), state.error, Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

额外检查点

  • 确认Retrofit实例配置正确:包含正确的baseUrl,添加了GsonConverterFactory(或其他序列化转换器)
  • 确认Hilt配置完整:Application类添加@HiltAndroidApp注解,ApiServices通过@Provides正确注入
  • 确认AndroidManifest.xml配置:
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true">
        ...
    </application>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:59:50