Android MVVM+Firebase应用RecyclerView无法显示Firestore数据求助
RecyclerView无法显示Firestore数据问题排查
我是Android Studio新手,正在学习基于Kotlin的MVVM+Firebase应用开发。已经创建了包含所有所需字段的ServiceOrder数据类,也实现了SOListingFragment和对应的SOListingAdapter,用来通过RecyclerView展示服务订单列表。现在能正常往Firebase里添加数据,但列表完全不显示Firestore中的内容,已经卡了好几周了。
预期效果是展示完整的服务订单列表,实际运行时列表为空。
相关代码
ServiceOrder数据类
data class ServiceOrder( val id: String="", val SO_numb: String="", val SO_title: String="", val SO_type: String="", val SO_description: String="", @ServerTimestamp val date: Date= Date(), )
SOListingFragment
@AndroidEntryPoint class SOListingFragment : Fragment() { val TAG: String = "SOListingFragment" lateinit var binding: FragmentSOListingBinding val viewModel: ServiceOrderViewModel by viewModels() val adapter by lazy { SOListingAdapter( onItemClicked = { pos, item -> } , onEditClicked = { pos, item -> } , onDeleteClicked = {pos, item ->}, ) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { binding = FragmentSOListingBinding.inflate(layoutInflater) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.recyclerView.adapter = adapter binding.button.setOnClickListener{ findNavController().navigate(R.id.action_SOListingFragment_to_SODetailFragment) } viewModel.getServiceOrders() viewModel.serviceOrder.observe(viewLifecycleOwner){ state -> when(state){ is UiState.Loading -> { binding.progressBar.show() } is UiState.Failure -> { binding.progressBar.hide() toast(state.error) } is UiState.Success->{ binding.progressBar.hide() adapter.updateList(state.data.toMutableList()) } } } } }
SOListingAdapter
class SOListingAdapter ( val onItemClicked: (Int, ServiceOrder)-> Unit, val onEditClicked: (Int, ServiceOrder)-> Unit, val onDeleteClicked: (Int, ServiceOrder)-> Unit, ): RecyclerView.Adapter<SOListingAdapter.MyViewHolder>(){ private var list: MutableList<ServiceOrder> = arrayListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val itemView = ItemSoLayoutBinding.inflate(LayoutInflater.from(parent.context),parent,false) return MyViewHolder(itemView) } fun updateList(list: MutableList<ServiceOrder>){ this.list = list notifyDataSetChanged() } override fun getItemCount(): Int { return list.size } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val item = list[position] Log.d("SOListingAdapter", "Binding item at position $position: $item") holder.bind(item) } inner class MyViewHolder(val binding: ItemSoLayoutBinding): RecyclerView.ViewHolder(binding.root) { fun bind(item: ServiceOrder){ binding.SoNumber.setText(item.SO_numb) binding.SoType.setText(item.SO_type) binding.SoDescription.setText(item.SO_description) binding.SoLayout.setOnClickListener{ onEditClicked.invoke(adapterPosition,item)} binding.itemLayout.setOnClickListener{onItemClicked.invoke(adapterPosition,item)} } } }
Firestore数据库结构
{ "collections":{ "serviceorder":{ "OInkAxPraLS4WgtqmzEV":{ "date":{ "datatype":"timestamp", "value":{ "_seconds":1719104689, "_nanoseconds":372000000 } }, "so_description":"ok my man", "so_numb":"140678", "so_type":"Inspection", "so_title":"No Power", "id":"OInkAxPraLS4WgtqmzEV", "collections":{ } }, "sFxKZZnx5V6RGeoBGwgd":{ "date":{ "datatype":"timestamp", "value":{ "_seconds":1719107360, "_nanoseconds":29000000 } }, "so_description":"aeet", "so_numb":"131493", "so_type":"Inspection", "so_title":"Maintenance", "id":"sFxKZZnx5V6RGeoBGwgd", "collections":{ } }, "y6P2kSN7pee86nmVVSF1":{ "date":{ "datatype":"timestamp", "value":{ "_seconds":1719773956, "_nanoseconds":425000000 } }, "so_description":"free to go man ", "so_numb":"143623", "so_type":"Fraud Case", "id":"y6P2kSN7pee86nmVVSF1", "so_title":"Inspection", "collections":{ } } } } }
问题排查与解决
1. 字段命名大小写不匹配
Firestore中的字段是小写开头(so_numb、so_type等),但数据类里是大写开头(SO_numb、SO_type),Firestore序列化时大小写敏感,导致字段无法映射,数据类对象的这些字段会被初始化为空值,列表项绑定后显示为空。
解决方式:
- 要么修改数据类字段名,和Firestore保持一致:
data class ServiceOrder( val id: String="", val so_numb: String="", val so_title: String="", val so_type: String="", val so_description: String="", @ServerTimestamp val date: Date= Date(), )
同时更新Adapter绑定代码:binding.SoNumber.setText(item.so_numb)
- 要么用
@PropertyName注解指定Firestore字段名:
data class ServiceOrder( val id: String="", @PropertyName("so_numb") val SO_numb: String="", @PropertyName("so_title") val SO_title: String="", @PropertyName("so_type") val SO_type: String="", @PropertyName("so_description") val SO_description: String="", @ServerTimestamp val date: Date= Date(), )
2. RecyclerView未设置LayoutManager
RecyclerView必须设置LayoutManager才能渲染列表项,代码中缺少这一步,即使有数据也无法显示。
解决方式:在onViewCreated中添加:
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
3. 检查ViewModel数据读取逻辑与Firestore权限
- 确认ViewModel的
getServiceOrders()方法正确查询serviceorder集合,并转换为ServiceOrder列表:
fun getServiceOrders() { serviceOrder.postValue(UiState.Loading) FirebaseFirestore.getInstance() .collection("serviceorder") .get() .addOnSuccessListener { snapshot -> val orders = snapshot.toObjects(ServiceOrder::class.java) serviceOrder.postValue(UiState.Success(orders)) } .addOnFailureListener { e -> serviceOrder.postValue(UiState.Failure(e.message ?: "Unknown error")) } }
- 检查Firestore安全规则,测试阶段可临时开放读写权限(后续需改为严格规则):
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if true; } } }
4. 添加日志排查
在Fragment的UiState.Success分支添加日志,确认是否获取到数据:
is UiState.Success->{ binding.progressBar.hide() Log.d(TAG, "获取到${state.data.size}条订单数据") adapter.updateList(state.data.toMutableList()) }
如果日志显示数据量为0,说明Firestore读取失败;如果数据量大于0但列表没显示,排查Adapter和RecyclerView配置。
内容的提问来源于stack exchange,提问作者Dexia
相关产品推荐
相关产品推荐

