You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
        }
    ]
}

问题分析与修复方案

核心问题点

  1. API响应解析不匹配:API返回单个对象(包含status、msg、data数组),但代码定义返回类型为List<model_doc>,导致Gson无法解析,response.body()为null。
  2. 模型字段不匹配:模型类Data的字段与JSON返回键名不一致(如JSON是doc_code,模型是doctor_id),无法映射数据。
  3. 适配器逻辑错误:适配器接收List<model_doc>但实际需展示model_doc内的data数组;且调用了不存在的getDoctor_app()方法,会触发空指针异常。
  4. 初始化风险: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 03:30:47