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

更换Data Class后RecyclerView显示为空的技术求助

RecyclerView显示空白问题:替换自定义数据类与接口后失效

问题概述

使用原MarsProperty数据类对接Mars接口时,RecyclerView正常显示数据;替换为自定义啤酒厂数据类并切换到对应接口后,RecyclerView显示为空。

原可正常工作的数据类

@Parcelize
data class MarsProperty (
        val id: String,
        // 映射JSON的img_src字段到类中的imgSrcUrl
        @Json(name = "img_src") val imgSrcUrl: String,
        val type: String,
        val price: Double) : Parcelable {
    val isRental
        get() = type == "rent"
}

自定义啤酒厂数据类

@Parcelize
data class MarsProperty (
@Json(name = "Bottom Fermentation")val Bottom_Fermentation: Int,
val Changed_time: Int,
val Contact_email: String,
val Contact_name: String,
@Json(name = "Contact_phone/mobile")val Contact_phone_mobile: String,
val Deleted: Int,
@Json(name = "Mixed Fermentation")val Mixed_Fermentation: String,
val Name: String,
val Opening_times_en: String,
val Opening_times_nl: String,
@Json(name = "Possibility for individuals to join groups_en") val groups_en: String,
@Json(name = "Possibility for individuals to join groups_nl") val groups_nl: String,
@Json(name = "Related links") val Related_links: String,
@Json(name = "Sponaneuous Fermentation") val Sponaneuous_Fermentation: String,
@Json(name = "Top Fermentation") val Top_Fermentation: Int,
val Website: String,
val box_number: String,
val city_name: String,
val copyrights: String,
val description_en: String,
val description_nl: String,
@Json(name = "e-mail") val email: String,
val fax: String,
val house_number: Int,
val imagesURL: String,
val mobile: String,
val phone: String,
@Json(name = "postal_ code")val postal_code: Int,
val province: String,
val street: String,
val videoURL: String): Parcelable {
    val joinGroup
        get() = groups_nl == "Ja"
}

相关组件代码

OverviewFragment

class OverviewFragment : Fragment() {

    private val viewModel: OverviewViewModel by lazy {
        ViewModelProvider(this).get(OverviewViewModel::class.java)
    }

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

        binding.lifecycleOwner = this

        binding.viewModel = viewModel

        binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
            viewModel.displayPropertyDetails(it)
        })

        viewModel.navigateToSelectedProperty.observe(this, Observer {
            if ( null != it ) {
                this.findNavController().navigate(OverviewFragmentDirections.actionShowDetail(it))
                viewModel.displayPropertyDetailsComplete()
            }
        })

        return binding.root
    }
}

OverviewViewModel

class OverviewViewModel : ViewModel() {

    private val _properties = MutableLiveData<List<MarsProperty>>()

    val properties: LiveData<List<MarsProperty>>
        get() = _properties

    private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
    val navigateToSelectedProperty: LiveData<MarsProperty>
        get() = _navigateToSelectedProperty

    init {
        getMarsRealEstateProperties()
    }

    private fun getMarsRealEstateProperties() {
        viewModelScope.launch {
            try {
                _properties.value = MarsApi.retrofitService.getProperties()
            } catch (e: Exception) {
                _properties.value = ArrayList()
            }
        }
    }

    fun displayPropertyDetails(marsProperty: MarsProperty) {
        _navigateToSelectedProperty.value = marsProperty
    }

    fun displayPropertyDetailsComplete() {
        _navigateToSelectedProperty.value = null
    }
}

PhotoGridAdapter

class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
        ListAdapter<MarsProperty,
                PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {

    class MarsPropertyViewHolder(private var binding: GridViewItemBinding):
            RecyclerView.ViewHolder(binding.root) {
        fun bind(marsProperty: MarsProperty) {
            binding.property = marsProperty
            binding.executePendingBindings()
        }
    }

    companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
        override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
            return oldItem === newItem
        }

        override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
            return oldItem.Name == newItem.Name
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup,
                                    viewType: Int): MarsPropertyViewHolder {
        return MarsPropertyViewHolder(GridViewItemBinding.inflate(LayoutInflater.from(parent.context)))
    }

    override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
        val marsProperty = getItem(position)
        holder.itemView.setOnClickListener {
            onClickListener.onClick(marsProperty)
        }
        holder.bind(marsProperty)
    }

    class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
        fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
    }
}

问题排查与解决方案

1. 接口数据结构不匹配

原Mars接口直接返回数组,而啤酒厂接口返回的是外层对象,数据数组嵌套在data字段中,导致Retrofit无法直接解析为List<MarsProperty>。

修改步骤:

  • 定义响应包装类:
data class BreweryResponse(
    val data: List<MarsProperty>
)
  • 更新Retrofit接口:
interface MarsApi {
    @GET("tourist/activities/breweries.json")
    suspend fun getProperties(): BreweryResponse
}
  • 调整ViewModel数据获取逻辑:
private fun getMarsRealEstateProperties() {
    viewModelScope.launch {
        try {
            val response = MarsApi.retrofitService.getProperties()
            _properties.value = response.data
        } catch (e: Exception) {
            e.printStackTrace() // 打印异常便于排查
            _properties.value = ArrayList()
        }
    }
}

2. 数据类字段类型不匹配

啤酒厂接口返回的部分字段为字符串类型,但自定义数据类错误定义为Int,导致JSON解析失败,触发异常后_properties.value被设为空列表。

修正数据类字段类型:

@Parcelize
data class MarsProperty (
@Json(name = "Bottom Fermentation")val Bottom_Fermentation: String,
val Changed_time: String,
val Contact_email: String,
val Contact_name: String,
@Json(name = "Contact_phone/mobile")val Contact_phone_mobile: String,
val Deleted: String,
@Json(name = "Mixed Fermentation")val Mixed_Fermentation: String,
val Name: String,
val Opening_times_en: String,
val Opening_times_nl: String,
@Json(name = "Possibility for individuals to join groups_en") val groups_en: String,
@Json(name = "Possibility for individuals to join groups_nl") val groups_nl: String,
@Json(name = "Related links") val Related_links: String,
@Json(name = "Sponaneuous Fermentation") val Sponaneuous_Fermentation: String,
@Json(name = "Top Fermentation") val Top_Fermentation: String,
val Website: String,
val box_number: String,
val city_name: String,
val copyrights: String,
val description_en: String,
val description_nl: String,
@Json(name = "e-mail") val email: String,
val fax: String,
val house_number: String,
val imagesURL: String,
val mobile: String,
val phone: String,
@Json(name = "postal_ code")val postal_code: String,
val province: String,
val street: String,
val videoURL: String): Parcelable {
    val joinGroup
        get() = groups_nl == "Ja"
}

3. 确认RecyclerView数据更新逻辑

fragment_overview.xml中使用了app:listData="@{viewModel.properties}",需确保存在对应的BindingAdapter自动更新Adapter数据:

添加BindingAdapter:

@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: List<MarsProperty>?) {
    val adapter = recyclerView.adapter as PhotoGridAdapter
    adapter.submitList(data)
}

也可直接在Fragment中手动观察数据更新:

// 在OverviewFragment的onCreateView中添加
viewModel.properties.observe(viewLifecycleOwner) {
    (binding.photosGrid.adapter as PhotoGridAdapter).submitList(it)
}

4. 添加异常日志

在ViewModel的getMarsRealEstateProperties中添加e.printStackTrace(),可查看解析或网络请求中的异常信息,快速定位问题。

内容的提问来源于stack exchange,提问作者im new no flame pls

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 14:18:09