【问题标题】:Android Retrofit2 onFailure returns 'Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $'Android Retrofit2 onFailure 返回“预期 BEGIN_ARRAY 但在第 1 行第 2 列路径 $ 处是 BEGIN_OBJECT”
【发布时间】:2018-01-18 16:56:59
【问题描述】:

我有一个应用程序正在查询端点,然后将响应简单地放在 ListView 中。但是,“onFailure”返回消息“预期 BEGIN_ARRAY 但在第 1 行第 2 列路径 $ 处为 BEGIN_OBJECT”。

我查看了类似的问题,但似乎无法在我的应用程序的上下文中弄清楚。

在 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”,这会导致它返回状态代码“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 而不是列表时才有效 - 在界面中也是如此。但是,我在正文中注意到它有一些空属性 - 这是一个问题吗?

而且,由于不让它作为列表返回,我无法让它填充我的列表视图 - 对此有什么想法吗?

【问题讨论】:

  • 您是否查看过使用 Postman 或其他类似工具获得的响应?
  • @ReneFerrari 感谢您的回复 - 我刚刚发布了更新(见上文)。所以看起来响应是一个对象......我想?但我现在想弄清楚的是如何在“_embedded”中访问它以及它应该如何出现在代码中,即它应该被声明为什么类型......
  • eventname 重命名为 name 并在上面添加注释 @Expose 然后它应该可以工作:)
  • 哦,对不起,我个人用给定的 JSON 响应来模拟 java 模型的是following
  • @ReneFerrari 感谢您的回复。所以我在我的“TicketMasterEvent”类中这样做了,但“名称”只是返回为空。为了让响应设置该变量,我需要做些什么,还是需要将模型设置为像响应一样?目前我只想打印整个内容,以便我知道它正在获取它

标签: android retrofit retrofit2 endpoint


【解决方案1】:

解决方案 1

因此,要将您的 JSON 响应映射到模型类,您只需使用 this 站点寻求帮助。源类型选择JSON,注释样式选择Gson。 结果应该是这样的(伪代码):

class TicketMasterEvent {
    @Expose
    Embedded embedded;
}

class Embedded {
    @Expose
    List<Event> events;
}

还有事件类。现在它可能会将embedded 吐出为_embedded,这并不像Java。要更改它,只需执行以下操作:

@SerializedName("_embedded")
Embedded embedded;

此注释告诉解析器将_embedded 映射到embedded。 哦耶,还必须创建一个模型类 Image

解决方案 2

更好但更复杂的方法是获取raw JSON response,然后迭代响应Object,这样您就可以访问JsonArray事件,这是唯一包含部分的数据响应。 here 描述了如何迭代 JsonObject。然后你只需要将JsonArray 转换为List&lt;Event&gt;。这可以像这样完成:

List<Event> events = mGson.fromJson(jsonArray.toString(), new TypeToken<List<Event>>(){}.getType());

仅供参考:您的Event 类当然可以使用解决方案 1 开头链接的站点生成。为此,只需复制数组中第一个对象的内容 :)。在那个Event 类中 List&lt;Image&gt; images 也存在用于映射来自 JSON 响应的图像。

希望这会有所帮助!

【讨论】:

  • 非常感谢!我将尝试第一个。我正在从我在其他地方读到的答案中思考一些事情,但这是一种稍微不同的方法,更有意义
  • 如果您还有任何问题,尽管问:) 我最迟明天会回答他们
  • 抱歉,还有一个问题 - 我将如何在我的界面中表示这些新模型? IE。嵌入式模型是否需要成为查询的一部分?再次感谢,我现在真的学到了很多关于这个领域的知识哈哈
  • 哦,我忘记了.. 将它保留为Call&lt;List&lt;TicketMasterEvent&gt;&gt;,就像现在一样:) 与 gson 结合的改造应该会自动映射所有内容:) 你的界面可以保持完全相同。只有它背后的模型会改变!
  • 好的,太好了!我可能会在稍后或明天试一试 - 我会告诉你我的进展情况:)
猜你喜欢
  • 2016-07-10
  • 2018-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多