Android Retrofit2 onFailure returns 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $'
Android Retrofit2 onFailure returns 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $'
我有一个应用程序正在查询端点,然后将响应简单地放在 ListView 中。但是,'onFailure' 正在 return 发送消息 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $'。
我看过类似的问题,但似乎无法在我的应用程序上下文中弄清楚。
在 OnCreate 中,我为端点设置了基础 URL,然后添加了我的 API 键,并调用了一个查询必要参数的接口:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
myLocationButton = findViewById(R.id.myLocationBtn);
myLocationButton.setOnClickListener(this);
eventList = findViewById(R.id.evenListView);
SearchView searchView = findViewById(R.id.searchView);
searchView.setIconified(false);
searchView.clearFocus();
String API_BASE_URL = "https://app.ticketmaster.com/discovery/v2/";
final String API_KEY = "HIDDEN";
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
HttpUrl originalHttpUrl = original.url();
HttpUrl url = originalHttpUrl.newBuilder()
.addQueryParameter("apikey", API_KEY)
.build();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder().url(url);
Request request = requestBuilder.build();
return chain.proceed(request);
}
}).build();
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(
GsonConverterFactory.create()
);
Retrofit retrofit = builder.client(httpClient).build();
ITicketMasterAPI event = retrofit.create(ITicketMasterAPI.class);
Call<List<TicketMasterEvent>> call = event.getLocalEvents("manchester",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
call.enqueue(new Callback<List<TicketMasterEvent>>() {
@Override
public void onResponse(Call<List<TicketMasterEvent>> call, Response<List<TicketMasterEvent>> response) {
List<TicketMasterEvent> events = response.body();
eventList.setAdapter(new TMEventAdapter(SearchActivity.this, events));
Toast.makeText(SearchActivity.this,"something happened", Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call<List<TicketMasterEvent>> call, Throwable t) {
RequestBody test = call.request().body();
Toast.makeText(SearchActivity.this, "didn't work", Toast.LENGTH_LONG).show();
}
});
}
这是查询界面:
public interface ITicketMasterAPI {
@GET("events.json")
Call <List<TicketMasterEvent>> getLocalEvents(
@Query("city") String city,
@Query("id") String id,
@Query("keyword") String keyword,
@Query("attractionId") String attractionId,
@Query("venueId") String venueId,
@Query("postalCode") String postalCode,
@Query("latlong") String latlong,
@Query("radius") String radius,
@Query("unit") String unit,
@Query("source") String source,
@Query("locale") String locale,
@Query("marketId") String marketId,
@Query("startDateTime") String startDateTime,
@Query("endDateTime") String endDateTime,
@Query("includeTBA") String includeTBA,
@Query("includeTBD") String includeTBD,
@Query("includeTest") String includeTest,
@Query("size") String size,
@Query("page") String page,
@Query("sort") String sort,
@Query("onsaleStartDateTime") String onsaleStartDateTime,
@Query("onsaleEndDateTime") String onsaleEndDateTime,
@Query("countryCode") String countryCode,
@Query("stateCode") String stateCode,
@Query("stateCode") String classificationName,
@Query("classificationId") String classificationId,
@Query("dmaId") String dmaId,
@Query("segmentId") String segmentId,
@Query("segmentName") String segmentName,
@Query("promoterId") String promoterId,
@Query("clientVisibility") String clientVisibility,
@Query("geoPoint") String geoPoint,
@Query("includeLicensedContent") String includeLicensedContent,
@Query("includeSpellcheck") String includeSpellcheck);
}
以及数据模型。目前我只想要名字:
public class TicketMasterEvent {
public String eventName;
public String getEventName() {
return eventName;
}
更新
我没有将所有列表更改为 'TicketMasterEvent' 类型,这导致它 return 状态代码为“200 - OK”。但是,正如建议的那样,我查看了 Postman 中的实际响应,这就是我得到的:
更新 2
我进行了以下更改...
public class TicketMasterEvent {
@SerializedName("_embedded")
EventEmbedded embedded;
public String getName() {
return name;
}
@SerializedName("name")
@Expose
private String name;
@SerializedName("type")
@Expose
private String type;
@SerializedName("id")
@Expose
private int id;
@SerializedName("test")
@Expose
private String test;
@SerializedName("url")
@Expose
private String url;
@SerializedName("locale")
@Expose
private String locale;
@SerializedName("images")
@Expose
private List<EventImages> images;
}
public class EventEmbedded {
@SerializedName("events")
@Expose
List<TicketMasterEvent> events;
}
更新 3 - 有效!
好的,这是我得到的回复:
这似乎只在调用类型为 TicketMasterEvent 而不是列表时才起作用——这在界面中也是一样的。但是,我在正文中注意到它有一些空属性——这是一个问题吗?
而且,由于没有将它 return 作为列表,我无法让它填充我的列表视图 - 对此有什么想法吗?
解决方案 1
因此,要将您的 JSON 响应映射到模型 class,您只需使用 this 网站寻求帮助。源类型只有 select JSON
,注释样式只有 Gson
。
结果应该看起来像这样(伪代码):
class TicketMasterEvent {
@Expose
Embedded embedded;
}
class Embedded {
@Expose
List<Event> events;
}
还有事件 class。现在它可能会将 embedded
吐出为 _embedded
,这并不是真正的 Java。要更改它,只需执行以下操作:
@SerializedName("_embedded")
Embedded embedded;
此注释告诉解析器将 _embedded
映射到 embedded
。
哦耶,还必须创建一个模型 class Image
。
解决方案 2
更好但更复杂的方法是获取 raw JSON response
然后遍历响应 Object
这样您就可以访问 JsonArray
事件这是唯一包含部分响应的数据。 here 描述了如何遍历 JsonObject
。然后你只需要将 JsonArray
转换为你的 List<Event>
。可以这样做:
List<Event> events = mGson.fromJson(jsonArray.toString(), new TypeToken<List<Event>>(){}.getType());
仅供参考:您的 Event
class 当然可以使用解决方案 1 开头链接的站点生成。要做到这一点,只需复制第一个对象的内容大批 :)。在那 Event
class
List<Image> images
也存在以映射来自 JSON
响应的图像。
希望对您有所帮助!
我有一个应用程序正在查询端点,然后将响应简单地放在 ListView 中。但是,'onFailure' 正在 return 发送消息 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $'。
我看过类似的问题,但似乎无法在我的应用程序上下文中弄清楚。
在 OnCreate 中,我为端点设置了基础 URL,然后添加了我的 API 键,并调用了一个查询必要参数的接口:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
myLocationButton = findViewById(R.id.myLocationBtn);
myLocationButton.setOnClickListener(this);
eventList = findViewById(R.id.evenListView);
SearchView searchView = findViewById(R.id.searchView);
searchView.setIconified(false);
searchView.clearFocus();
String API_BASE_URL = "https://app.ticketmaster.com/discovery/v2/";
final String API_KEY = "HIDDEN";
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
HttpUrl originalHttpUrl = original.url();
HttpUrl url = originalHttpUrl.newBuilder()
.addQueryParameter("apikey", API_KEY)
.build();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder().url(url);
Request request = requestBuilder.build();
return chain.proceed(request);
}
}).build();
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(
GsonConverterFactory.create()
);
Retrofit retrofit = builder.client(httpClient).build();
ITicketMasterAPI event = retrofit.create(ITicketMasterAPI.class);
Call<List<TicketMasterEvent>> call = event.getLocalEvents("manchester",
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
call.enqueue(new Callback<List<TicketMasterEvent>>() {
@Override
public void onResponse(Call<List<TicketMasterEvent>> call, Response<List<TicketMasterEvent>> response) {
List<TicketMasterEvent> events = response.body();
eventList.setAdapter(new TMEventAdapter(SearchActivity.this, events));
Toast.makeText(SearchActivity.this,"something happened", Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call<List<TicketMasterEvent>> call, Throwable t) {
RequestBody test = call.request().body();
Toast.makeText(SearchActivity.this, "didn't work", Toast.LENGTH_LONG).show();
}
});
}
这是查询界面:
public interface ITicketMasterAPI {
@GET("events.json")
Call <List<TicketMasterEvent>> getLocalEvents(
@Query("city") String city,
@Query("id") String id,
@Query("keyword") String keyword,
@Query("attractionId") String attractionId,
@Query("venueId") String venueId,
@Query("postalCode") String postalCode,
@Query("latlong") String latlong,
@Query("radius") String radius,
@Query("unit") String unit,
@Query("source") String source,
@Query("locale") String locale,
@Query("marketId") String marketId,
@Query("startDateTime") String startDateTime,
@Query("endDateTime") String endDateTime,
@Query("includeTBA") String includeTBA,
@Query("includeTBD") String includeTBD,
@Query("includeTest") String includeTest,
@Query("size") String size,
@Query("page") String page,
@Query("sort") String sort,
@Query("onsaleStartDateTime") String onsaleStartDateTime,
@Query("onsaleEndDateTime") String onsaleEndDateTime,
@Query("countryCode") String countryCode,
@Query("stateCode") String stateCode,
@Query("stateCode") String classificationName,
@Query("classificationId") String classificationId,
@Query("dmaId") String dmaId,
@Query("segmentId") String segmentId,
@Query("segmentName") String segmentName,
@Query("promoterId") String promoterId,
@Query("clientVisibility") String clientVisibility,
@Query("geoPoint") String geoPoint,
@Query("includeLicensedContent") String includeLicensedContent,
@Query("includeSpellcheck") String includeSpellcheck);
}
以及数据模型。目前我只想要名字:
public class TicketMasterEvent {
public String eventName;
public String getEventName() {
return eventName;
}
更新
我没有将所有列表更改为 'TicketMasterEvent' 类型,这导致它 return 状态代码为“200 - OK”。但是,正如建议的那样,我查看了 Postman 中的实际响应,这就是我得到的:
更新 2
我进行了以下更改...
public class TicketMasterEvent {
@SerializedName("_embedded")
EventEmbedded embedded;
public String getName() {
return name;
}
@SerializedName("name")
@Expose
private String name;
@SerializedName("type")
@Expose
private String type;
@SerializedName("id")
@Expose
private int id;
@SerializedName("test")
@Expose
private String test;
@SerializedName("url")
@Expose
private String url;
@SerializedName("locale")
@Expose
private String locale;
@SerializedName("images")
@Expose
private List<EventImages> images;
}
public class EventEmbedded {
@SerializedName("events")
@Expose
List<TicketMasterEvent> events;
}
更新 3 - 有效!
好的,这是我得到的回复:
这似乎只在调用类型为 TicketMasterEvent 而不是列表时才起作用——这在界面中也是一样的。但是,我在正文中注意到它有一些空属性——这是一个问题吗?
而且,由于没有将它 return 作为列表,我无法让它填充我的列表视图 - 对此有什么想法吗?
解决方案 1
因此,要将您的 JSON 响应映射到模型 class,您只需使用 this 网站寻求帮助。源类型只有 select JSON
,注释样式只有 Gson
。
结果应该看起来像这样(伪代码):
class TicketMasterEvent {
@Expose
Embedded embedded;
}
class Embedded {
@Expose
List<Event> events;
}
还有事件 class。现在它可能会将 embedded
吐出为 _embedded
,这并不是真正的 Java。要更改它,只需执行以下操作:
@SerializedName("_embedded")
Embedded embedded;
此注释告诉解析器将 _embedded
映射到 embedded
。
哦耶,还必须创建一个模型 class Image
。
解决方案 2
更好但更复杂的方法是获取 raw JSON response
然后遍历响应 Object
这样您就可以访问 JsonArray
事件这是唯一包含部分响应的数据。 here 描述了如何遍历 JsonObject
。然后你只需要将 JsonArray
转换为你的 List<Event>
。可以这样做:
List<Event> events = mGson.fromJson(jsonArray.toString(), new TypeToken<List<Event>>(){}.getType());
仅供参考:您的 Event
class 当然可以使用解决方案 1 开头链接的站点生成。要做到这一点,只需复制第一个对象的内容大批 :)。在那 Event
class
List<Image> images
也存在以映射来自 JSON
响应的图像。
希望对您有所帮助!