改造预期BEGIN_OBJECT但BEGIN_ARRAY

2022-08-31 11:56:53

我对JSON解析相当陌生,我正在使用Square的改造库,并遇到了这个问题。

我正在尝试解析此 JSON 响应:

[
      {
        "id": 3,
        "username": "jezer",
        "regid": "oiqwueoiwqueoiwqueoiwq",
        "url": "http:\/\/192.168.63.175:3000\/users\/3.json"
      },
      {
        "id": 4,
        "username": "emulator",
        "regid": "qwoiuewqoiueoiwqueoq",
        "url": "http:\/\/192.168.63.175:3000\/users\/4.json"
      },
      {
        "id": 7,
        "username": "test",
        "regid": "ksadqowueqiaksj",
        "url": "http:\/\/192.168.63.175:3000\/users\/7.json"
      }
]

这是我的模型:

public class Contacts {

    public List<User> contacts;

}

...

public class User {

    String username;
    String regid;

    @Override
    public String toString(){
        return(username);
    }  

}

我的界面:

public interface ContactsInterface {

    @GET("/users.json")
    void contacts(Callback<Contacts> cb);

}

我的成功方法:

@Override
public void success(Contacts c, Response r) {
    List<String> names = new ArrayList<String>();
    for (int i = 0; i < c.contacts.size(); i++) {
        String name = c.contacts.get(i).toString();
        Log.d("Names", "" + name);
        names.add(name);
    }
    ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, names);
    mSentTo.setAdapter(spinnerAdapter);
}

当我在我的成功方法上使用它时,它会抛出错误

预期BEGIN_OBJECT,但在第 1 行第 2 列BEGIN_ARRAY

这是怎么回事?


答案 1

现在,您正在解析响应,就好像它的格式如下:

{
  "contacts": [
    { .. }
  ]
}

异常告诉您这一点,因为您期望在根目录下有一个对象,但实际数据实际上是一个数组。这意味着您需要将类型更改为数组。

最简单的方法是在回调中使用列表作为直接类型:

@GET("/users.json")
void contacts(Callback<List<User>> cb);

答案 2

dependencies used :

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

json 响应可以是两者的组合,也可以是两者的组合。见以下三种情况array responseobject response

案例 1:解析 json 数组响应(OP 的情况)

这种情况适用于那些形式为 [{...} ,{...}]json responses

例如:

[
  {
    "id": 3,
    "username": "jezer",
    "regid": "oiqwueoiwqueoiwqueoiwq",
    "url": "http:\/\/192.168.63.175:3000\/users\/3.json"
  },
  .
  .
]

首先为此数组创建一个模型类,或者只是转到jsonschema2pojo并自动生成一个,如下所示

Contacts.java

public class Contacts {

@SerializedName("id")
@Expose
private Integer id;
@SerializedName("username")
@Expose
private String username;
@SerializedName("regid")
@Expose
private String regid;
@SerializedName("url")
@Expose
private String url;

public Integer getId() {
return id;
}

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

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getRegid() {
return regid;
}

public void setRegid(String regid) {
this.regid = regid;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

}

ContactsInterface

在这种情况下,您应该返回如下所示的对象列表

public interface ContactsInterface {
@GET("/users.json")
Call<List<Contacts>> getContacts();
}

然后像下面这样拨打电话retrofit2

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("baseurl_here")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ContactsInterface request = retrofit.create(ContactsInterface.class);
    Call<List<Contacts>> call = request.getContacts();
    call.enqueue(new Callback<List<Contacts>>() {
        @Override
        public void onResponse(Call<List<Contacts>> call, Response<List<Contacts>> response) {
            Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call<List<Contacts>> call, Throwable t) {
            Log.e("Error",t.getMessage());
        }
    });

response.body()将为您提供对象列表

您也可以查看以下两种情况以供参考

Case 2 : Parsing a json object response

这种情况适用于那些格式为 {..} 的 json 响应。

例如:

{
"id": 3,
"username": "jezer",
"regid": "oiqwueoiwqueoiwqueoiwq",
"url": "http:\/\/192.168.63.175:3000\/users\/3.json"
}

在这里,我们有与上面相同的示例。因此,模型类将是相同的,但像上面的例子一样,我们没有这些对象的数组 - 只有一个对象,因此我们不需要将其解析为列表。object

因此,请对object response

public interface ContactsInterface {
    @GET("/users.json")
    Call<Contacts> getContacts();
    }

然后像下面这样拨打电话retrofit2

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("baseurl_here")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ContactsInterface request = retrofit.create(ContactsInterface.class);
    Call<Contacts> call = request.getContacts();
    call.enqueue(new Callback<Contacts>() {
        @Override
        public void onResponse(Call<Contacts> call, Response<Contacts> response) {
            Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call<Contacts> call, Throwable t) {
            Log.e("Error",t.getMessage());
        }
    });

response.body()会给你对象

您还可以在解析json对象响应时检查常见错误:“预期begin_array但begin_object”

Case 3 : Parsing a json array inside json object

这种情况适用于那些形式为{“array_name”:[{...} ,{...}]}json responses

例如:

    {
    "contacts": 
         [
            {
             "id": 3,
             "username": "jezer",
             "regid": "oiqwueoiwqueoiwqueoiwq",
             "url": "http:\/\/192.168.63.175:3000\/users\/3.json"
            }
         ]
    }

这里需要两个模型类,因为我们有两个对象(一个在数组外部,一个在数组内部)。生成如下

ContactWrapper

public class ContactWrapper {

@SerializedName("contacts")
@Expose
private List<Contacts> contacts = null;

public List<Contacts> getContacts() {
return contacts;
}

public void setContacts(List<Contacts> contacts) {
this.contacts = contacts;
}

}

您可以使用上面生成的联系人.java列表对象(为案例 1 生成)

因此,请对object response

public interface ContactsInterface {
    @GET("/users.json")
    Call<ContactWrapper> getContacts();
    }

然后像下面这样拨打电话retrofit2

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("baseurl_here")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    ContactsInterface request = retrofit.create(ContactsInterface.class);
    Call<ContactWrapper> call = request.getContacts();
    call.enqueue(new Callback<ContactWrapper>() {
        @Override
        public void onResponse(Call<ContactWrapper> call, Response<ContactWrapper> response) {
            Toast.makeText(MainActivity.this,response.body().getContacts().toString(),Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call<ContactWrapper> call, Throwable t) {
            Log.e("Error",t.getMessage());
        }
    });

在这里,与案例1的区别在于,我们应该使用而不是获取对象列表response.body().getContacts()response.body()

上述案例的一些参考:

案例 1:解析 json 数组响应,案例 2:解析 json 对象响应,混合:在另一个 json 对象内解析 json 数组