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

如何在setOnClickListener内部调用ViewModel中的数据实现重试加载

问题根因

崩溃主要来自两个问题:

  1. 嵌套lambda默认参数名it冲突:外层observe回调的it是返回的Resource数据对象,内层点击事件的it是被点击的View控件对象,直接复用写法会拿错对象触发类型转换异常。
  2. 代码写法的潜在风险:你把重试点击事件的设置放在了observe的ERROR分支中,每次触发ERROR回调都会重复添加点击监听器,可能导致一次点击触发多次请求;另外代码中用!!强转可空对象也容易触发空指针崩溃。

解决方案

重试逻辑不需要你在点击事件中重复写列表更新代码,只要点击时触发ViewModel重新拉取数据,请求成功后LiveData会自动触发回调,走你已经写好的SUCCESS分支更新列表即可。建议抽离公共方法避免嵌套lambda冲突,同时优化代码稳定性:

步骤1:抽离公共复用方法

// 触发ViewModel请求新闻数据,替换为你ViewModel中实际的请求方法名
private fun loadNews() {
    homeViewModel.fetchNewsList()
}

// 成功拿到数据后更新列表
private fun updateNewsList(newsData: List<你的新闻数据类型>?) {
    newsData ?: return // 空数据直接返回,避免崩溃
    // 优化:不要每次成功都新建Adapter,复用现有Adapter只更新数据性能更好
    if (newsAdapter == null) {
        newsAdapter = NewsAdapter(newsData)
        binding.rvNews.adapter = newsAdapter
    } else {
        newsAdapter.setNewData(newsData) // 需在Adapter中新增更新数据的方法,配合DiffUtil使用效果更好
    }
}

// 展示错误页UI
private fun showErrorPage() {
    binding.newsError.tvError.visibility = View.VISIBLE
    binding.newsError.btnRetry.visibility = View.VISIBLE
    binding.tvNewsTitle.visibility = View.INVISIBLE
}

// 隐藏错误页UI
private fun hideErrorPage() {
    binding.newsError.tvError.visibility = View.GONE
    binding.newsError.btnRetry.visibility = View.GONE
    binding.tvNewsTitle.visibility = View.VISIBLE
}

步骤2:调整事件设置与Observer逻辑

// 初始化时就设置重试按钮点击事件,只设置一次避免重复添加
binding.newsError.btnRetry.setOnClickListener {
    loadNews()
}

// 观察ViewModel返回的数据,这里把默认的it重命名为resource,彻底避免参数名冲突
homeViewModel.newsResult.observe(viewLifecycleOwner) { resource ->
    when (resource.status) {
        Resource.Status.LOADING -> {
            hideErrorPage()
            // 可添加加载中状态逻辑,比如展示骨架屏、加载动画
        }
        Resource.Status.SUCCESS -> {
            hideErrorPage()
            updateNewsList(resource.data)
        }
        Resource.Status.ERROR -> {
            showErrorPage()
        }
    }
}

// 页面首次加载触发请求
loadNews()

额外优化建议

  • 禁止用!!强转可空对象,所有可空参数都做好空判断再使用,避免不必要的崩溃。
  • Adapter更新数据时建议使用DiffUtil计算新旧数据差异,只更新变化的Item,大幅提升列表滑动性能。
  • 如果不需要保留之前的加载状态,可以在ViewModel的请求方法中先把newsResult的状态置为LOADING再发起网络请求,保证点击重试后立即展示加载状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:54:01