如何正确解析嵌套JSONArray并在RecyclerView中展示
Hey there! Let's fix this up into a cleaner, more maintainable approach—your current method works, but we can eliminate those messy null checks and make the RecyclerView handling more robust. Here's how to do it properly:
Step 1: Define Type-Safe Data Models
Instead of using a single CustomerResponse class with nullable fields, create distinct classes for each item type you want to display. This makes your code type-safe and avoids null-related bugs.
// Base class to mark item types abstract class RecyclerViewItem { public enum ItemType { HEADER, CONTENT } abstract public ItemType getItemType(); } // For header items (the "Title" entries) class HeaderItem extends RecyclerViewItem { private final String title; public HeaderItem(String title) { this.title = title; } public String getTitle() { return title; } @Override public ItemType getItemType() { return ItemType.HEADER; } } // For content items (the nested "Content" entries) class ContentItem extends RecyclerViewItem { private final String field1; private final boolean field2; public ContentItem(String field1, boolean field2) { this.field1 = field1; this.field2 = field2; } public String getField1() { return field1; } public boolean isField2() { return field2; } @Override public ItemType getItemType() { return ItemType.CONTENT; } } // Keep your existing model classes for JSON parsing class ApiResponse { private String Status; private List<ResponseArrayObject> Response; // Getters and Setters } class ResponseArrayObject { private String Title; private String Code; private List<Content> Content; // Getters and Setters } class Content { private String field_1; private boolean field_2; // Getters and Setters }
Step 2: Parse JSON & Build Your RecyclerView Item List
First, parse the full API response properly (instead of just the Response array), then build your list using the type-safe item classes:
// Parse the full JSON response ApiResponse apiResponse = new Gson().fromJson(jsonString, ApiResponse.class); List<ResponseArrayObject> responseList = apiResponse.getResponse(); // Build the RecyclerView item list List<RecyclerViewItem> recyclerViewItems = new ArrayList<>(); for (ResponseArrayObject responseO : responseList) { if (responseO.getContent() != null && !responseO.getContent().isEmpty()) { // Add header item first recyclerViewItems.add(new HeaderItem(responseO.getTitle())); // Add all corresponding content items for (Content content : responseO.getContent()) { recyclerViewItems.add(new ContentItem(content.getField_1(), content.isField_2())); } } }
Step 3: Build a Multi-Type RecyclerView Adapter
Create an adapter that handles each item type explicitly, no more checking for null values. This keeps your binding logic clean and scalable:
public class MultiTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int VIEW_TYPE_HEADER = 0; private static final int VIEW_TYPE_CONTENT = 1; private final List<RecyclerViewItem> itemList; public MultiTypeAdapter(List<RecyclerViewItem> itemList) { this.itemList = itemList; } @Override public int getItemViewType(int position) { RecyclerViewItem item = itemList.get(position); return switch (item.getItemType()) { case HEADER -> VIEW_TYPE_HEADER; case CONTENT -> VIEW_TYPE_CONTENT; }; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); if (viewType == VIEW_TYPE_HEADER) { View view = inflater.inflate(R.layout.item_header, parent, false); return new HeaderViewHolder(view); } else { View view = inflater.inflate(R.layout.item_content, parent, false); return new ContentViewHolder(view); } } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { RecyclerViewItem item = itemList.get(position); if (holder instanceof HeaderViewHolder headerHolder) { HeaderItem headerItem = (HeaderItem) item; headerHolder.titleTextView.setText(headerItem.getTitle()); } else if (holder instanceof ContentViewHolder contentHolder) { ContentItem contentItem = (ContentItem) item; contentHolder.field1TextView.setText(contentItem.getField1()); contentHolder.field2CheckBox.setChecked(contentItem.isField2()); } } @Override public int getItemCount() { return itemList.size(); } // ViewHolder for header items static class HeaderViewHolder extends RecyclerView.ViewHolder { TextView titleTextView; HeaderViewHolder(@NonNull View itemView) { super(itemView); titleTextView = itemView.findViewById(R.id.tv_header_title); } } // ViewHolder for content items static class ContentViewHolder extends RecyclerView.ViewHolder { TextView field1TextView; CheckBox field2CheckBox; ContentViewHolder(@NonNull View itemView) { super(itemView); field1TextView = itemView.findViewById(R.id.tv_field1); field2CheckBox = itemView.findViewById(R.id.cb_field2); } } }
Why This Approach Is Better
- Type Safety: No more nullable fields or ambiguous data structures—each item class only holds the data it needs.
- Maintainability: Adding new item types (like dividers or empty states) only requires creating a new
RecyclerViewItemsubclass and updating the adapter slightly. - Readability: Anyone looking at your code can immediately tell what each item type does and how it's rendered.
- Null Safety: Eliminates the risk of null pointer exceptions from checking nullable fields in the adapter.
内容的提问来源于stack exchange,提问作者Joe

