更换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
相关产品推荐
相关产品推荐

