Android开发新手求助:含子项的JSON适配SimpleAdapter与AsyncTask问题
搞定带回复的评论列表:别用嵌套ListView,试试这招!
兄弟,我太懂你这种卡壳的滋味了——折腾好几天,数据能拿到就是显示不出来,对着带嵌套的JSON抓头发,搜了一堆资料还是没头绪,简直崩溃😤
先给你划重点:别用ListView嵌套ListView!这种方案看似直观,但会带来严重的性能问题,滚动时卡顿、复用混乱都是常有的事,Android官方也不推荐这种嵌套滚动的实现方式。针对你这种「评论+子回复」的层级结构,有两个更靠谱的选择,我给你一步步拆解:
第一步:先把JSON数据映射成Java对象
首先得把杂乱的JSON转换成清晰的实体类,方便后续操作。根据你给的JSON示例,我们可以定义两个类:
Comment(评论类)
public class Comment { private String comentariosId; private String noticiasId; private String content; // 假设评论内容字段叫这个,你可以根据实际JSON调整 private List<Reply> replies; // 存储该评论下的所有回复 // 构造方法、getter、setter自己补全哈 }
Reply(回复类)
public class Reply { private String replyId; private String commentId; private String content; // 同样补全构造方法、getter、setter }
然后在AsyncTask的doInBackground里解析JSON:
@Override protected List<Comment> doInBackground(Void... voids) { List<Comment> commentList = new ArrayList<>(); try { JSONObject jsonObject = new JSONObject(你的JSON字符串); JSONArray comentariosArray = jsonObject.getJSONArray("COMENTARIOS"); for (int i = 0; i < comentariosArray.length(); i++) { JSONObject commentObj = comentariosArray.getJSONObject(i); Comment comment = new Comment(); comment.setComentariosId(commentObj.getString("comentarios_id")); comment.setNoticiasId(commentObj.getString("noticias_id")); // 其他评论字段同理 // 解析回复(假设回复字段叫RESPUESTAS,你根据实际JSON调整) if (commentObj.has("RESPUESTAS")) { JSONArray repliesArray = commentObj.getJSONArray("RESPUESTAS"); List<Reply> replyList = new ArrayList<>(); for (int j = 0; j < repliesArray.length(); j++) { JSONObject replyObj = repliesArray.getJSONObject(j); Reply reply = new Reply(); reply.setReplyId(replyObj.getString("respuestas_id")); // 示例字段,按需调整 reply.setContent(replyObj.getString("content")); replyList.add(reply); } comment.setReplies(replyList); } commentList.add(comment); } } catch (JSONException e) { e.printStackTrace(); } return commentList; }
第二步:选对列表组件,两种方案任你挑
方案一:用ExpandableListView(新手友好)
这个组件天生就是为「父项+子项」的层级结构设计的,不用自己处理嵌套滚动的坑,实现起来最简单:
- 布局文件:在你的Activity布局里加入ExpandableListView
<ExpandableListView android:id="@+id/expandable_list" android:layout_width="match_parent" android:layout_height="match_parent"/>
写父项(评论)和子项(回复)的布局:
- 评论布局(item_comment.xml):放评论的内容、时间、作者这些元素
- 回复布局(item_reply.xml):样式可以比评论稍缩进,区分层级
自定义ExpandableListAdapter:
public class CommentExpandableAdapter extends BaseExpandableListAdapter { private Context mContext; private List<Comment> mCommentList; public CommentExpandableAdapter(Context context, List<Comment> commentList) { this.mContext = context; this.mCommentList = commentList; } @Override public int getGroupCount() { return mCommentList.size(); } @Override public int getChildrenCount(int groupPosition) { Comment comment = mCommentList.get(groupPosition); return comment.getReplies() != null ? comment.getReplies().size() : 0; } @Override public Object getGroup(int groupPosition) { return mCommentList.get(groupPosition); } @Override public Object getChild(int groupPosition, int childPosition) { return mCommentList.get(groupPosition).getReplies().get(childPosition); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public boolean hasStableIds() { return false; } // 渲染评论父项 @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_comment, parent, false); } Comment comment = (Comment) getGroup(groupPosition); // 绑定评论数据到布局控件,比如TextView显示内容 TextView commentContent = convertView.findViewById(R.id.tv_comment_content); commentContent.setText(comment.getContent()); // 其他字段同理 return convertView; } // 渲染回复子项 @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_reply, parent, false); } Reply reply = (Reply) getChild(groupPosition, childPosition); TextView replyContent = convertView.findViewById(R.id.tv_reply_content); replyContent.setText(reply.getContent()); return convertView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; // 允许点击回复项 } }
- 在AsyncTask的onPostExecute里设置Adapter:
@Override protected void onPostExecute(List<Comment> commentList) { super.onPostExecute(commentList); ExpandableListView expandableListView = findViewById(R.id.expandable_list); CommentExpandableAdapter adapter = new CommentExpandableAdapter(YourActivity.this, commentList); expandableListView.setAdapter(adapter); }
方案二:用RecyclerView(更灵活)
如果以后需要更复杂的交互(比如评论点赞、回复输入),RecyclerView会更灵活。你可以:
- 给每个评论Item里嵌套一个小的RecyclerView来显示回复,但要注意给这个子RecyclerView设置固定高度,或者用
NestedScrollView配合recyclerView.setNestedScrollingEnabled(false)来避免滚动冲突。 - 或者用多类型Item,把评论和回复都当成不同类型的Item,通过位置来判断层级(但需要自己处理缩进和布局区分)。不过这个方案对新手来说稍复杂,先把ExpandableListView搞懂再尝试也不迟。
最后提个醒
你之前用的SimpleAdapter只适合扁平的一维数据,没法处理这种嵌套结构,所以必须自定义Adapter才行。另外AsyncTask现在已经被官方标记为过时了,新项目里可以考虑用Coroutines或者ExecutorService来做异步任务,但你现在先把功能跑通,后续再优化也没问题。
按这个步骤来,应该能搞定你的评论列表了,加油!
内容的提问来源于stack exchange,提问作者user2950020
相关产品推荐
相关产品推荐

