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

Retrofit解析JSON报错:Expected BEGIN_ARRAY but was BEGIN_OBJECT问题解决

解决Gson解析错误:"Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $"

问题背景

作为Android开发者首次遇到上述Gson解析错误,怀疑问题出在Model层或数据适配逻辑中。

接口响应(Postman返回)

{
  "Status": 200,
  "Message": "OK",
  "Data": {
    "ServiceTypes": [
      {
        "Id": 1,
        "ServiceTypeNameAr": "صيانة",
        "ServiceTypeNameEn": "Maintenance",
        "MainServices": [
          {
            "Id": 11,
            "ServiceTypeId": 1,
            "MainServiceNameAr": "تكييفات\r\n",
            "MainServiceNameEn": "Air conditioning\r\n",
            "SubServices": null
          },
          {
            "Id": 12,
            "ServiceTypeId": 1,
            "MainServiceNameAr": "كهرباء\r\n",
            "MainServiceNameEn": "Electricity\r\n",
            "SubServices": null
          },
          {
            "Id": 14,
            "ServiceTypeId": 1,
            "MainServiceNameAr": "سباكة",
            "MainServiceNameEn": "Plumbing\r\n",
            "SubServices": null
          },
          {
            "Id": 15,
            "ServiceTypeId": 1,
            "MainServiceNameAr": "اجهزة منزلية\r\n",
            "MainServiceNameEn": "Home appliances\r\n",
            "SubServices": null
          }
          
        ]
     }
      
    ]
    
  }
  
}

现有Model与接口代码

ResponseModel

public class ResponseModel {
    @SerializedName("Status")
    public int Status;
    @SerializedName("Message")
    public String Message;
    @SerializedName("Data")
    public DataModel Data;

    public int getStatus() {
        return Status;
    }

    public void setStatus(int status) {
        Status = status;
    }

    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }

    public DataModel getData() {
        return Data;
    }

    public void setData(DataModel data) {
        this.Data = data;
    }
}

DataModel

public class DataModel {
    @SerializedName("Country")
    private List<CountryModel> countryModels;
    @SerializedName("Users")
    private List<UserModel> users;
    @SerializedName("Cities")
    private List<CityItem> cityItems;
    @SerializedName("ServiceTypes")
    private List<ServiceTypeModel> serviceTypeModels;
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    public List<CityItem> getCityItems() {
        return cityItems;
    }

    public void setCityItems(List<CityItem> cityItems) {
        this.cityItems = cityItems;
    }

    public List<UserModel> getUsers() {
        return users;
    }

    public void setUsers(ArrayList<UserModel> users) {
        this.users = users;
    }

    public List<CountryModel> getCountryModels() {
        return countryModels;
    }

    public void setCountryModels(ArrayList<CountryModel> countryModels) {
        this.countryModels = countryModels;
    }
    public List<ServiceTypeModel> getServiceTypeModels() {
        return serviceTypeModels;
    }

    public void setServiceTypeModels(List<ServiceTypeModel> serviceTypeModels) {
        this.serviceTypeModels = serviceTypeModels;
    }

    public void setCountryModels(List<CountryModel> countryModels) {
        this.countryModels = countryModels;
    }

    public void setUsers(List<UserModel> users) {
        this.users = users;
    }

    public Map<String, Object> getAdditionalProperties() {
        return additionalProperties;
    }

    public void setAdditionalProperties(Map<String, Object> additionalProperties) {
        this.additionalProperties = additionalProperties;
    }
}

ServiceTypeModel

public class ServiceTypeModel {
    @SerializedName("Id")
    private int id;
    @SerializedName("ServiceTypeNameAr")
    private String serviceTypeNameAr;
    @SerializedName("ServiceTypeNameEn")
    private String serviceTypeNameEn;
    @SerializedName("MainServices")
    private List<MainServicesModel> mainServicesList;

    public List<MainServicesModel> getMainServicesList() {
        return mainServicesList;
    }

    public void setMainServicesList(List<MainServicesModel> mainServicesList) {
        this.mainServicesList = mainServicesList;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getServiceTypeNameAr() {
        return serviceTypeNameAr;
    }

    public void setServiceTypeNameAr(String serviceTypeNameAr) {
        this.serviceTypeNameAr = serviceTypeNameAr;
    }

    public String getServiceTypeNameEn() {
        return serviceTypeNameEn;
    }

    public void setServiceTypeNameEn(String serviceTypeNameEn) {
        this.serviceTypeNameEn = serviceTypeNameEn;
    }
}

接口定义

public interface ServiceTypeInterface {
    @GET("ServiceType")
    Call<ResponseModel> GetServicesType(@Header("authorization") String token);

    @GET("ServiceType/{id}")
    Call<ResponseModel> GetServiceTypeById(@Path("id") int Id, @Header("authorization") String token);
}

RecyclerView适配器

public class ServiceTypeAdapter extends RecyclerView.Adapter<ServiceTypeAdapter.ServiceTypeHolder> {
    private List<ResponseModel> serviceTypeModels = new ArrayList<>();
    private final ServiceTypeListener listener;
    private Context context;

    public ServiceTypeAdapter(ServiceTypeListener listener, Context context, List<ResponseModel> serviceTypeList) {
        this.listener = listener;
        this.context = context;
        this.serviceTypeModels = serviceTypeList;
    }

    @NonNull
    @Override
    public ServiceTypeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sub_service, parent, false);
        return new ServiceTypeHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ServiceTypeHolder holder, int position) {
        final ResponseModel ServiceType = serviceTypeModels.get(position);
        holder.TxtServiceTypeName.setText(ServiceType.getData().getServiceTypeModels().get(0).getServiceTypeNameEn());
    }

    @Override
    public int getItemCount() {
        return serviceTypeModels.size();
    }

    public long getItemId(int position) {
        return position;
    }

    public void setList(List<ResponseModel> serviceTypeModels) {
        this.serviceTypeModels = serviceTypeModels;
        notifyDataSetChanged();
    }

    public class ServiceTypeHolder extends RecyclerView.ViewHolder {
        TextView TxtServiceTypeName;
        public ServiceTypeHolder(@NonNull View itemView) {
            super(itemView);
            TxtServiceTypeName = itemView.findViewById(R.id.ServiceTypeName);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    listener.onServiceTypeSelected(serviceTypeModels.get(getAdapterPosition()));
                }
            });
        }
    }

    public interface ServiceTypeListener {
        void onServiceTypeSelected(ResponseModel serviceTypeModel);
    }
}

问题排查

错误核心原因:Gson期望解析数组(BEGIN_ARRAY),但实际接收到的是对象(BEGIN_OBJECT)。结合代码来看,问题出在RecyclerView适配器的数据源逻辑:

  1. 接口返回单个ResponseModel对象,而非List<ResponseModel>数组
  2. 适配器错误将List<ResponseModel>作为数据源,且onBindViewHolder中强行取第一个元素的ServiceType,逻辑完全错误——实际要展示的是ResponseModel.Data.ServiceTypes列表

另外,代码未提供MainServicesModel定义,需确保该Model存在,否则解析MainServices数组时也会报错。

解决方案

1. 修正RecyclerView适配器

将数据源改为List<ServiceTypeModel>,直接对应接口返回的ServiceTypes列表:

public class ServiceTypeAdapter extends RecyclerView.Adapter<ServiceTypeAdapter.ServiceTypeHolder> {
    private List<ServiceTypeModel> serviceTypeModels = new ArrayList<>();
    private final ServiceTypeListener listener;
    private Context context;

    public ServiceTypeAdapter(ServiceTypeListener listener, Context context) {
        this.listener = listener;
        this.context = context;
    }

    @NonNull
    @Override
    public ServiceTypeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sub_service, parent, false);
        return new ServiceTypeHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ServiceTypeHolder holder, int position) {
        ServiceTypeModel serviceType = serviceTypeModels.get(position);
        holder.TxtServiceTypeName.setText(serviceType.getServiceTypeNameEn());
    }

    @Override
    public int getItemCount() {
        return serviceTypeModels.size();
    }

    public long getItemId(int position) {
        return position;
    }

    public void setList(List<ServiceTypeModel> serviceTypeModels) {
        this.serviceTypeModels = serviceTypeModels;
        notifyDataSetChanged();
    }

    public class ServiceTypeHolder extends RecyclerView.ViewHolder {
        TextView TxtServiceTypeName;
        public ServiceTypeHolder(@NonNull View itemView) {
            super(itemView);
            TxtServiceTypeName = itemView.findViewById(R.id.ServiceTypeName);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    listener.onServiceTypeSelected(serviceTypeModels.get(getAdapterPosition()));
                }
            });
        }
    }

    public interface ServiceTypeListener {
        void onServiceTypeSelected(ServiceTypeModel serviceTypeModel);
    }
}

2. 修正接口调用后的数据源传递

在Retrofit回调中,取出ServiceTypes列表传给适配器:

// 示例调用代码
ServiceTypeInterface service = RetrofitClient.getInstance().create(ServiceTypeInterface.class);
Call<ResponseModel> call = service.GetServicesType("your_token_here");
call.enqueue(new Callback<ResponseModel>() {
    @Override
    public void onResponse(Call<ResponseModel> call, Response<ResponseModel> response) {
        if (response.isSuccessful() && response.body() != null) {
            List<ServiceTypeModel> serviceTypes = response.body().getData().getServiceTypeModels();
            serviceTypeAdapter.setList(serviceTypes);
        }
    }

    @Override
    public void onFailure(Call<ResponseModel> call, Throwable t) {
        // 处理失败逻辑
    }
});

3. 补充MainServicesModel定义

确保存在对应的MainServicesModel类,匹配接口返回的MainServices结构:

public class MainServicesModel {
    @SerializedName("Id")
    private int id;
    @SerializedName("ServiceTypeId")
    private int serviceTypeId;
    @SerializedName("MainServiceNameAr")
    private String mainServiceNameAr;
    @SerializedName("MainServiceNameEn")
    private String mainServiceNameEn;
    @SerializedName("SubServices")
    private List<Object> subServices; // 根据实际SubServices结构替换泛型

    // Getter和Setter方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public int getServiceTypeId() { return serviceTypeId; }
    public void setServiceTypeId(int serviceTypeId) { this.serviceTypeId = serviceTypeId; }
    public String getMainServiceNameAr() { return mainServiceNameAr; }
    public void setMainServiceNameAr(String mainServiceNameAr) { this.mainServiceNameAr = mainServiceNameAr; }
    public String getMainServiceNameEn() { return mainServiceNameEn; }
    public void setMainServiceNameEn(String mainServiceNameEn) { this.mainServiceNameEn = mainServiceNameEn; }
    public List<Object> getSubServices() { return subServices; }
    public void setSubServices(List<Object> subServices) { this.subServices = subServices; }
}

验证要点

  • 确认Retrofit配置中使用了GsonConverterFactory,且Gson实例配置正确
  • 检查接口返回的JSON格式是否与Model类的@SerializedName完全匹配
  • 确保ServiceTypes字段在DataModel中定义为List<ServiceTypeModel>,与JSON中的数组结构对应

内容的提问来源于stack exchange,提问作者Mohammad khaled

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:24:36