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

Android Fragment中LiveData数据不显示,旋转屏幕后正常的问题求助

问题排查与解决方案

核心问题分析

你的代码存在两个关键问题导致RecyclerView初始不显示数据:

1. RecyclerView未设置LayoutManager

RecyclerView必须指定LayoutManager才能确定子项的排列布局方式(线性、网格等),你的MainPageFragment中仅为RecyclerView设置了Adapter,但未设置LayoutManager,这会导致RecyclerView无法渲染任何子项。

2. Adapter数据更新未通知RecyclerView

ShopAppRecyclerViewAdapter中直接给products属性赋值,但没有调用notifyDataSetChanged()(或相关通知方法),RecyclerView无法感知数据变化,因此不会更新UI。

而屏幕旋转后能显示的原因:

  • 配置变更后Fragment重建,ViewModel保留了之前请求到的数据,Observer订阅LiveData时会立刻收到已有数据;
  • 重建后的RecyclerView在绑定Adapter后,会触发一次初始布局(此时Adapter的products已经有数据),但这只是巧合,并非正确的实现方式。

修复步骤

步骤1:为RecyclerView添加LayoutManager

修改MainPageFragment的onCreateView方法,为两个RecyclerView设置LayoutManager(这里以横向线性布局为例,可根据需求调整):

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    binding = FragmentMainPageBinding.inflate(inflater, container, false)

    val recyclerviewLatestProducts = binding.recyclerViewLatestProduct
    val recyclerviewProductsOnDiscont = binding.recyclerViewProductsOnDiscont

    // 添加LayoutManager,指定布局方式
    recyclerviewLatestProducts.layoutManager = LinearLayoutManager(requireContext(), LinearLayout.HORIZONTAL, false)
    recyclerviewProductsOnDiscont.layoutManager = LinearLayoutManager(requireContext(), LinearLayout.HORIZONTAL, false)

    val adapterLatestProduct = ShopAppRecyclerViewAdapter()
    val adapterProductsOnDiscont = ShopAppRecyclerViewAdapter()

    recyclerviewLatestProducts.adapter = adapterLatestProduct
    recyclerviewProductsOnDiscont.adapter = adapterProductsOnDiscont

    viewModel.getLatestProduct().observe(viewLifecycleOwner, {
        adapterLatestProduct.products = it
        // 通知RecyclerView数据更新
        adapterLatestProduct.notifyDataSetChanged()
    })

    viewModel.getProductOnDiscont().observe(viewLifecycleOwner) {
        adapterProductsOnDiscont.products = it
        // 通知RecyclerView数据更新
        adapterProductsOnDiscont.notifyDataSetChanged()
    }

    viewModel.getDataAboutProductsFromNetwork()

    return binding.root
}

步骤2:优化Adapter的数据更新逻辑(可选但推荐)

为了避免每次设置数据都手动调用通知方法,可修改Adapter的products属性,通过setter自动触发刷新:

class ShopAppRecyclerViewAdapter : RecyclerView.Adapter<ShopAppViewHolder>() {
    // 改为私有字段,通过setter控制更新逻辑
    private var _products = listOf<Product>()
    var products: List<Product>
        get() = _products
        set(value) {
            _products = value
            notifyDataSetChanged()
        }

    // 其余原有代码保持不变...
}

修改后,Fragment中只需执行adapterLatestProduct.products = it即可,无需手动调用notifyDataSetChanged()。

额外优化:使用DiffUtil提升性能(可选)

如果数据量较大,notifyDataSetChanged()会刷新整个列表,推荐使用DiffUtil实现局部刷新,提升性能:

class ShopAppRecyclerViewAdapter : RecyclerView.Adapter<ShopAppViewHolder>() {
    private var _products = listOf<Product>()
    var products: List<Product>
        get() = _products
        set(value) {
            val diffResult = DiffUtil.calculateDiff(ProductDiffCallback(_products, value))
            _products = value
            diffResult.dispatchUpdatesTo(this)
        }

    // 实现DiffCallback,用于对比新旧数据
    class ProductDiffCallback(private val oldList: List<Product>, private val newList: List<Product>) : DiffUtil.Callback() {
        override fun getOldListSize() = oldList.size
        override fun getNewListSize() = newList.size
        
        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            // 根据Product的唯一标识判断是否为同一项目(示例用name,实际建议用id)
            val oldItem = oldList[oldItemPosition]
            val newItem = newList[newItemPosition]
            return when {
                oldItem is Product.Latest && newItem is Product.Latest -> oldItem.name == newItem.name
                oldItem is Product.FlashSale && newItem is Product.FlashSale -> oldItem.name == newItem.name
                else -> false
            }
        }
        
        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            // 判断内容是否完全一致,需确保Product类正确实现equals方法
            return oldList[oldItemPosition] == newList[newItemPosition]
        }
    }

    // 其余原有代码保持不变...
}

其他注意点

  • 确保Product类正确实现equals()方法(使用DiffUtil时需要),否则无法准确判断内容是否变化;
  • 可在ViewModel的processData方法中添加日志,确认网络请求返回的数据是否有效、非空;
  • 检查Dagger2的注入逻辑,确保component.inject(this)中的component已正确初始化。

内容的提问来源于stack exchange,提问作者Влад Михнёнок

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:37:59