Nested RecyclerView+Firebase调用push()插入数据时报反序列化错误
嵌套RecyclerView对接Firebase反序列化报错修复
问题现象
实现嵌套RecyclerView对接Firebase Realtime Database时,调用push()方法添加数据后,读取数据抛出如下错误:
Expected a List while deserializing, but got a class java.util.HashMap
问题相关原代码
MainActivity核心逻辑
AlertDialog dialog; IFirebaseLoadListener iFirebaseLoadListener; RecyclerView my_recycler_view; DatabaseReference myData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myData= FirebaseDatabase.getInstance().getReference("MyData"); dialog= new SpotsDialog.Builder().setContext(this).build(); iFirebaseLoadListener = this; // 初始化视图 my_recycler_view= (RecyclerView)findViewById(R.id.my_recycler_view); my_recycler_view.setHasFixedSize(true); my_recycler_view.setLayoutManager(new LinearLayoutManager(this)); // 加载数据 getFirebaseData(); } private void getFirebaseData() { dialog.show(); myData.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { List<itemGroup> itemGroups= new ArrayList<>(); for(DataSnapshot groupSnapshot: dataSnapshot.getChildren()) { itemGroup itemGroup= new itemGroup(); itemGroup.setHeaderTitle(groupSnapshot.child("headerTitle").getValue(true).toString()); GenericTypeIndicator<ArrayList<itemData>> genericTypeIndicator= new GenericTypeIndicator<ArrayList<itemData>>(){} ; // 此处存在未定义key变量、直接强转ArrayList的错误 itemGroup.setListItem(groupSnapshot.child("listItem").child(key).getValue(genericTypeIndicator)); itemGroups.add(itemGroup); } iFirebaseLoadListener.onFirebaseLoadSuccess(itemGroups); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { iFirebaseLoadListener.onFirebaseLoadFailed(databaseError.getMessage()); } }); } @Override public void onFirebaseLoadSuccess(List<itemGroup> itemGroupList) { MyItemGroupAdapter adapter = new MyItemGroupAdapter(this,itemGroupList); my_recycler_view.setAdapter(adapter); dialog.dismiss(); } @Override public void onFirebaseLoadFailed(String message) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); dialog.dismiss(); }
实体类定义
public class itemData { private String name ,image; public itemData() {} public itemData(String name, String image) { this.name = name; this.image = image; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } } public class itemGroup { private String headerTitle; private ArrayList<itemData> listItem; public itemGroup() {} public itemGroup(String headerTitle, ArrayList<itemData> listItem) { this.headerTitle = headerTitle; this.listItem = listItem; } public String getHeaderTitle() { return headerTitle; } public void setHeaderTitle(String headerTitle) { this.headerTitle = headerTitle; } public ArrayList<itemData> getListItem() { return listItem; } public void setListItem(ArrayList<itemData> listItem) { this.listItem = listItem; } }
适配器代码
public class MyItemAdapter extends RecyclerView.Adapter<MyItemAdapter.MyViewHolder> { private Context context; private List<itemData> itemDataList; public MyItemAdapter(Context context, List<itemData> itemDataList) { this.context = context; this.itemDataList = itemDataList; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View itemView = LayoutInflater.from(context).inflate(R.layout.layout_item,viewGroup,false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) { myViewHolder.txt_item_titles.setText(itemDataList.get(i).getName()); Picasso.get().load(itemDataList.get(i).getImage()).into(myViewHolder.img_item); myViewHolder.setiItemClickListener(new IItemClickListener() { @Override public void onItemClickListener(View view, int i) { Toast.makeText(context, ""+ itemDataList.get(i).getName(), Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return (itemDataList != null ? itemDataList.size() : 0); } public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView txt_item_titles; ImageView img_item; IItemClickListener iItemClickListener; public void setiItemClickListener(IItemClickListener iItemClickListener) { this.iItemClickListener = iItemClickListener; } public MyViewHolder (View itemView ){ super(itemView); txt_item_titles= (TextView)itemView.findViewById(R.id.tvTitle); img_item= (ImageView) itemView.findViewById(R.id.itemImage); itemView.setOnClickListener(this); } @Override public void onClick(View v) { iItemClickListener.onItemClickListener(v,getAdapterPosition()); } } } public class MyItemGroupAdapter extends RecyclerView.Adapter<MyItemGroupAdapter.MyViewHolder> { private Context context; private List<itemGroup> dataList; public MyItemGroupAdapter(Context context, List<itemGroup> dataList) { this.context = context; this.dataList = dataList; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View itemView = LayoutInflater.from(context).inflate(R.layout.layout_group,viewGroup,false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int i) { myViewHolder.item_title.setText(dataList.get(i).getHeaderTitle()); List<itemData> itemData = dataList.get(i).getListItem(); MyItemAdapter itemListAdapter=new MyItemAdapter(context,itemData); myViewHolder.recycler_view_item_list.setHasFixedSize(true); myViewHolder.recycler_view_item_list.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false)); myViewHolder.recycler_view_item_list.setAdapter(itemListAdapter); myViewHolder.recycler_view_item_list.setNestedScrollingEnabled(false); myViewHolder.btn_more.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(context, "Button More "+ myViewHolder.item_title.getText(), Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return (dataList != null ? dataList.size() : 0); } public class MyViewHolder extends RecyclerView.ViewHolder{ TextView item_title ; RecyclerView recycler_view_item_list; Button btn_more; public MyViewHolder (View itemView ){ super (itemView); item_title= (TextView) itemView.findViewById(R.id.itemTitle); btn_more= (Button)itemView.findViewById(R.id.btMore); recycler_view_item_list= (RecyclerView)itemView.findViewById(R.id.recycler_view_list); } } }
报错根因
- Firebase Realtime Database 底层没有数组/List类型的存储结构,当调用
push()方法添加子节点时,Firebase会自动生成随机字符串作为节点key,此时listItem节点下的结构实际是key为pushID、value为itemData对象的HashMap结构,不是有序数组结构。 - 原代码直接使用
GenericTypeIndicator<ArrayList<itemData>>尝试将HashMap结构直接反序列化为ArrayList,触发类型不匹配错误。 - 原代码中
groupSnapshot.child("listItem").child(key)的key变量未定义,本身存在逻辑错误。
修复方案
修改getFirebaseData()方法中读取listItem的逻辑,不要直接强转ArrayList,手动遍历listItem下的所有子节点,逐个转换为itemData对象后组装为ArrayList,修复后的核心代码如下:
@Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { List<itemGroup> itemGroups= new ArrayList<>(); for(DataSnapshot groupSnapshot: dataSnapshot.getChildren()) { itemGroup itemGroup= new itemGroup(); itemGroup.setHeaderTitle(groupSnapshot.child("headerTitle").getValue(true).toString()); // 手动遍历listItem节点组装列表 ArrayList<itemData> itemList = new ArrayList<>(); for (DataSnapshot itemSnapshot : groupSnapshot.child("listItem").getChildren()) { itemData data = itemSnapshot.getValue(itemData.class); itemList.add(data); } itemGroup.setListItem(itemList); itemGroups.add(itemGroup); } iFirebaseLoadListener.onFirebaseLoadSuccess(itemGroups); }
注:类名建议遵循Java大驼峰命名规范,将
itemGroup、itemData改为ItemGroup、ItemData,避免后续出现类识别相关问题。
内容的提问来源于stack exchange,提问作者Alexandru Sirbu
相关产品推荐
相关产品推荐

