Android开发:解析嵌套JSON并绑定RecyclerView遇阻求助
Android API数据绑定RecyclerView问题排查与修复
问题背景
开发Android应用时,需传入clinic_id调用API获取JSON响应,将数据绑定到RecyclerView,但过程中出现数据解析失败、页面无展示等异常,现有代码无法正常工作。
现有代码
主Activity类(today_doctors)
public class today_doctors extends AppCompatActivity { viewModel_doc listViewModel; List<model_doc> datalist; todayDoctorAdapter adapter; TextView clinic_name; RecyclerView recview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_today_doctors); recview=findViewById(R.id.rv); recview.setLayoutManager(new LinearLayoutManager(this)); recview.addItemDecoration(new DividerItemDecoration(this, 0)); adapter=new todayDoctorAdapter(datalist); recview.setAdapter(adapter); clinic_name=findViewById(R.id.tvDrName); process(); } public void process(){ listViewModel= new ViewModelProvider(this).get(viewModel_doc.class); listViewModel.getDatalistObserver ().observe(this, new Observer<List<model_doc>>() { @Override public void onChanged(List<model_doc> Models) { if(Models!=null) { datalist= Models; adapter.updateList(Models); } else { recview.setVisibility(View.GONE); Toast.makeText(today_doctors.this, "No data recieved", Toast.LENGTH_SHORT).show(); } } }); listViewModel.makeApiCall(); }
ViewModel类(viewModel_doc)
public class viewModel_doc extends ViewModel { private MutableLiveData<List<model_doc>> datalist2; public viewModel_doc(){ datalist2=new MutableLiveData<>(); } public MutableLiveData<List<model_doc>> getDatalistObserver() { return datalist2; } public void makeApiCall() { apiSet apiServices= apiController.getInstance().getApi(); Call<List<model_doc>> calldoc=apiServices.getList2("ll0004"); calldoc.enqueue(new Callback<List<model_doc>>() { @Override public void onResponse(Call<List<model_doc>> call, Response<List<model_doc>> response) { datalist2.postValue(response.body()); } @Override public void onFailure(Call<List<model_doc>> call, Throwable t) { datalist2.postValue(null); Log.e("Error :",t.getMessage()); } }); } }
数据模型类(model_doc)
public class model_doc { String status,msg; ArrayList<Data> data; public model_doc(String status, String msg, ArrayList<Data> data) { this.status = status; this.msg = msg; this.data = data; } public String getStatus() { return status; } public String getMsg() { return msg; } public ArrayList<Data> getData() { return data; } public static class Data { String doctor_id; String doctor_name; String proposed_date; String date; // Getters setters public Data(String doctor_id, String doctor_name, String proposed_date, String date) { this.doctor_id = doctor_id; this.doctor_name = doctor_name; this.proposed_date = proposed_date; this.date = date; } public String getDoctor_id() { return doctor_id; } public String getDoctor_name() { return doctor_name; } public String getProposed_date() { return proposed_date; } public String getDate() { return date; } } }
API接口(apiSet)
@FormUrlEncoded @POST("doctor_list") Call<List<model_doc>>getList2( @Field("clinic_id") String clinic_id );
Retrofit控制器(apiController)
public class apiController { private static final String url="https://xyz.in/api/"; private static apiController clientObject; private static Retrofit retrofit; apiController() { retrofit=new Retrofit.Builder() .baseUrl(url) .addConverterFactory(GsonConverterFactory.create()) .build(); } public static synchronized apiController getInstance(){ if(clientObject==null) clientObject=new apiController(); return clientObject; } public apiSet getApi(){ return retrofit.create(apiSet.class); } }
RecyclerView适配器(todayDoctorAdapter)
public class todayDoctorAdapter extends RecyclerView.Adapter<todayDoctorAdapter.viewholder> { List<model_doc> datalist2; public todayDoctorAdapter(List<model_doc> list){ this.datalist2=list;} public void updateList(List<model_doc>list){ this.datalist2=list; notifyDataSetChanged(); } @NonNull @Override public todayDoctorAdapter.viewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_doctors,parent,false); return new todayDoctorAdapter.viewholder(view); } @Override public void onBindViewHolder(@NonNull todayDoctorAdapter.viewholder holder, int position){ holder.doctor_name.setText(String.format("Dr.%s", datalist2.get(position).getDoctor_app())); holder.proposed_date.setText(String.format("Apt: %s","TODAY")); String doc=datalist2.get(position).getDoctor_app(); holder.cv.setOnClickListener( new View.OnClickListener(){ @Override public void onClick(View arg0) { Intent intent = new Intent(arg0.getContext(), PatientsUnderDoctor.class); intent.putExtra("doc_name", doc); arg0.getContext().startActivity(intent); } }); } @Override public int getItemCount(){ if (this.datalist2!=null){ return this.datalist2.size(); } return 0; } public static class viewholder extends RecyclerView.ViewHolder{ TextView doctor_name,proposed_date; CardView cv; public viewholder(@NonNull View itemView) { super(itemView); doctor_name=itemView.findViewById(R.id.drName); proposed_date=itemView.findViewById(R.id.apptDate); cv=itemView.findViewById(R.id.cv_patient); } } }
API返回的JSON格式
{ "status": "success", "msg": "Found", "data": [ { "doc_code": "jhjh0001", "app_date": "2022-09-13", "doc_name": "kjk", "count": 1 } ] }
问题分析与修复方案
核心问题点
- API响应解析不匹配:API返回单个对象(包含
status、msg、data数组),但代码定义返回类型为List<model_doc>,导致Gson无法解析,response.body()为null。 - 模型字段不匹配:模型类
Data的字段与JSON返回键名不一致(如JSON是doc_code,模型是doctor_id),无法映射数据。 - 适配器逻辑错误:适配器接收
List<model_doc>但实际需展示model_doc内的data数组;且调用了不存在的getDoctor_app()方法,会触发空指针异常。 - 初始化风险:
datalist初始为null,直接传入适配器可能导致后续更新异常。
修复步骤
1. 修正API接口返回类型
将接口返回类型改为单个model_doc对象,匹配API实际响应结构:
@FormUrlEncoded @POST("doctor_list") Call<model_doc> getList2(@Field("clinic_id") String clinic_id);
2. 更新ViewModel数据逻辑
调整ViewModel的LiveData类型为List<model_doc.Data>,并在API响应中提取data数组:
public class viewModel_doc extends ViewModel { private MutableLiveData<List<model_doc.Data>> datalist2; public viewModel_doc(){ datalist2=new MutableLiveData<>(); } public MutableLiveData<List<model_doc.Data>> getDatalistObserver() { return datalist2; } public void makeApiCall() { apiSet apiServices= apiController.getInstance().getApi(); Call<model_doc> calldoc=apiServices.getList2("ll0004"); calldoc.enqueue(new Callback<model_doc>() { @Override public void onResponse(Call<model_doc> call, Response<model_doc> response) { if(response.isSuccessful() && response.body() != null) { datalist2.postValue(response.body().getData()); } else { datalist2.postValue(null); } } @Override public void onFailure(Call<model_doc> call, Throwable t) { datalist2.postValue(null); Log.e("Error :",t.getMessage()); } }); } }
3. 修正模型类字段映射
更新Data类字段与JSON键名一致,添加@SerializedName确保映射正确:
public class model_doc { String status,msg; ArrayList<Data> data; // 保留原有构造、getter方法 public static class Data { @SerializedName("doc_code") String doctor_id; @SerializedName("doc_name") String doctor_name; @SerializedName("app_date") String date; int count; public Data(String doctor_id, String doctor_name, String date, int count) { this.doctor_id = doctor_id; this.doctor_name = doctor_name; this.date = date; this.count = count; } // 对应getter方法 public String getDoctor_id() { return doctor_id; } public String getDoctor_name() { return doctor_name; } public String getDate() { return date; } public int getCount() { return count; } } }
4. 调整主Activity观察者逻辑
初始化datalist为空列表,适配新的LiveData类型:
public class today_doctors extends AppCompatActivity { viewModel_doc listViewModel; List<model_doc.Data> datalist = new ArrayList<>(); todayDoctorAdapter adapter; // 其他变量 @Override protected void onCreate(Bundle savedInstanceState) { // 原有初始化代码 adapter=new todayDoctorAdapter(datalist); recview.setAdapter(adapter); // ... } public void process(){ listViewModel= new ViewModelProvider(this).get(viewModel_doc.class); listViewModel.getDatalistObserver().observe(this, new Observer<List<model_doc.Data>>() { @Override public void onChanged(List<model_doc.Data> dataList) { if(dataList!=null && !dataList.isEmpty()) { datalist= dataList; adapter.updateList(dataList); recview.setVisibility(View.VISIBLE); } else { recview.setVisibility(View.GONE); Toast.makeText(today_doctors.this, "未获取到数据", Toast.LENGTH_SHORT).show(); } } }); listViewModel.makeApiCall(); } }
5. 修复适配器数据绑定逻辑
更新适配器接收List<model_doc.Data>,并正确绑定字段:
public class todayDoctorAdapter extends RecyclerView.Adapter<todayDoctorAdapter.viewholder> { List<model_doc.Data> datalist2; public todayDoctorAdapter(List<model_doc.Data> list){ this.datalist2=list; } public void updateList(List<model_doc.Data> list){ this.datalist2=list; notifyDataSetChanged(); } @NonNull @Override public viewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_doctors,parent,false); return new viewholder(view); } @Override public void onBindViewHolder(@NonNull viewholder holder, int position){ model_doc.Data doctorData = datalist2.get(position); holder.doctor_name.setText(String.format("Dr.%s", doctorData.getDoctor_name())); holder.proposed_date.setText(String.format("Apt: %s", doctorData.getDate())); String docName = doctorData.getDoctor_name(); holder.cv.setOnClickListener(v -> { Intent intent = new Intent(v.getContext(), PatientsUnderDoctor.class); intent.putExtra("doc_name", docName); v.getContext().startActivity(intent); }); } @Override public int getItemCount(){ return datalist2 != null ? datalist2.size() : 0; } public static class viewholder extends RecyclerView.ViewHolder{ TextView doctor_name,proposed_date; CardView cv; public viewholder(@NonNull View itemView) { super(itemView); doctor_name=itemView.findViewById(R.id.drName); proposed_date=itemView.findViewById(R.id.apptDate); cv=itemView.findViewById(R.id.cv_patient); } } }
内容的提问来源于stack exchange,提问作者GoingVintage
相关产品推荐
相关产品推荐

